Browse Source

Merge branch 'release-poc-4'

Conflicts:
	README.md
	libethereum/Instruction.cpp
	libethereum/Instruction.h
	libethereum/PeerNetwork.cpp
cl-refactor
Gav Wood 11 years ago
parent
commit
472b5451a4
  1. 3
      .gitignore
  2. 10
      CMakeLists.txt
  3. 8
      README.md
  4. 7
      alethzero/CMakeLists.txt
  5. 168
      alethzero/Main.ui
  6. 301
      alethzero/MainWin.cpp
  7. 23
      alethzero/MainWin.h
  8. 6
      debian/README.Debian
  9. 9
      debian/README.source
  10. 23
      debian/changelog
  11. 1
      debian/compat
  12. 29
      debian/control
  13. 24
      debian/copyright
  14. 3
      debian/docs
  15. 36
      debian/rules
  16. 48
      eth-ncurses-cli/CMakeLists.txt
  17. 1109
      eth-ncurses-cli/main.cpp
  18. 4
      eth/CMakeLists.txt
  19. 161
      eth/main.cpp
  20. 8
      libethereum/AddressState.cpp
  21. 39
      libethereum/AddressState.h
  22. 4
      libethereum/BlockChain.cpp
  23. 3
      libethereum/BlockChain.h
  24. 13
      libethereum/CMakeLists.txt
  25. 59
      libethereum/Client.cpp
  26. 19
      libethereum/Client.h
  27. 280
      libethereum/Common.cpp
  28. 617
      libethereum/Common.h
  29. 95
      libethereum/CommonData.cpp
  30. 195
      libethereum/CommonData.h
  31. 189
      libethereum/CommonEth.cpp
  32. 137
      libethereum/CommonEth.h
  33. 48
      libethereum/CommonIO.cpp
  34. 223
      libethereum/CommonIO.h
  35. 36
      libethereum/CryptoHeaders.h
  36. 11
      libethereum/Dagger.cpp
  37. 3
      libethereum/Dagger.h
  38. 14
      libethereum/Exceptions.h
  39. 43
      libethereum/ExtVMFace.h
  40. 32
      libethereum/FeeStructure.cpp
  41. 22
      libethereum/FeeStructure.h
  42. 25
      libethereum/FixedHash.cpp
  43. 195
      libethereum/FixedHash.h
  44. 809
      libethereum/Instruction.cpp
  45. 123
      libethereum/Instruction.h
  46. 54
      libethereum/Log.cpp
  47. 134
      libethereum/Log.h
  48. 1084
      libethereum/PeerNetwork.cpp
  49. 169
      libethereum/PeerNetwork.h
  50. 562
      libethereum/PeerServer.cpp
  51. 136
      libethereum/PeerServer.h
  52. 587
      libethereum/PeerSession.cpp
  53. 90
      libethereum/PeerSession.h
  54. 11
      libethereum/RLP.h
  55. 316
      libethereum/State.cpp
  56. 117
      libethereum/State.h
  57. 27
      libethereum/Transaction.cpp
  58. 31
      libethereum/Transaction.h
  59. 1
      libethereum/TransactionQueue.cpp
  60. 16
      libethereum/TrieDB.h
  61. 1
      libethereum/UPnP.cpp
  62. 30
      libethereum/VM.cpp
  63. 568
      libethereum/VM.h
  64. 11
      libethereum/vector_ref.h
  65. 8
      package.sh
  66. 74
      release.sh
  67. 2
      test/CMakeLists.txt
  68. 32
      test/JsonSpiritHeaders.h
  69. 15
      test/MemTrie.cpp
  70. 3
      test/MemTrie.h
  71. 49
      test/TestHelper.cpp
  72. 30
      test/TestHelper.h
  73. 15
      test/TrieHash.cpp
  74. 3
      test/TrieHash.h
  75. 24
      test/boostTest.cpp
  76. 38
      test/crypto.cpp
  77. 1
      test/dagger.cpp
  78. 56
      test/fork.cpp
  79. 8
      test/hexPrefix.cpp
  80. 9
      test/main.cpp
  81. 51
      test/network.cpp
  82. 2
      test/peer.cpp
  83. 8
      test/rlp.cpp
  84. 13
      test/trie.cpp
  85. 117
      test/txTest.cpp
  86. 221
      test/vm.cpp
  87. 115
      walleth/CMakeLists.txt
  88. 168
      walleth/Main.ui
  89. 448
      walleth/MainWin.cpp
  90. 224
      walleth/MainWin.h
  91. 5
      walleth/Resources.qrc
  92. 38
      walleth/Simple.qml
  93. 11
      walleth/main.cpp
  94. 12
      windows/Ethereum.sln
  95. 8
      windows/LibCryptoPP.vcxproj
  96. 2
      windows/LibEthereum.props
  97. 31
      windows/LibEthereum.vcxproj
  98. 47
      windows/LibEthereum.vcxproj.filters
  99. 8
      windows/LibLevelDB.vcxproj
  100. 8
      windows/LibMiniUPnPc.vcxproj

3
.gitignore

@ -19,9 +19,6 @@ ipch
*.opensdf *.opensdf
*.suo *.suo
# Generated headers
*.h
*.user *.user
*.user.* *.user.*
*~ *~

10
CMakeLists.txt

@ -17,6 +17,10 @@ if ("x${TARGET_PLATFORM}" STREQUAL "x")
set(TARGET_PLATFORM "linux") set(TARGET_PLATFORM "linux")
endif () endif ()
if ("${TARGET_PLATFORM}" STREQUAL "linux")
set(CMAKE_THREAD_LIBS_INIT pthread)
endif ()
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_NAME Windows)
@ -58,7 +62,7 @@ else ()
endif () endif ()
# Initialize CXXFLAGS. # Initialize CXXFLAGS.
set(CMAKE_CXX_FLAGS "-Wall -std=c++11") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG")
@ -150,8 +154,12 @@ add_subdirectory(test)
add_subdirectory(eth) add_subdirectory(eth)
if (NOT HEADLESS) if (NOT HEADLESS)
add_subdirectory(alethzero) add_subdirectory(alethzero)
add_subdirectory(walleth)
endif () endif ()
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)
unset(HEADLESS CACHE) unset(HEADLESS CACHE)
#unset(TARGET_PLATFORM CACHE) #unset(TARGET_PLATFORM CACHE)

8
README.md

@ -8,7 +8,11 @@ Contributors, builders and testers include Eric Lombrozo (cross-compilation), Ti
### Building ### Building
<<<<<<< HEAD
See [Build Instructions](https://github.com/ethereum/cpp-ethereum/wiki/Build-Instructions) and [Compatibility Info and Build Tips](https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips). See [Build Instructions](https://github.com/ethereum/cpp-ethereum/wiki/Build-Instructions) and [Compatibility Info and Build Tips](https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips).
=======
See https://github.com/ethereum/cpp-ethereum/wiki/Build-Instructions and https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips .
>>>>>>> release-poc-4
### Testing ### Testing
@ -16,7 +20,11 @@ To run the tests, make sure you clone the tests repository from github.com/ether
### Yet To Do ### Yet To Do
<<<<<<< HEAD
See [TODO](TODO) See [TODO](TODO)
=======
See https://github.com/ethereum/cpp-ethereum/wiki/TODO
>>>>>>> release-poc-4
### License ### License

7
alethzero/CMakeLists.txt

@ -20,10 +20,14 @@ if (APPLE)
include_directories(/usr/local/opt/qt5/include /usr/local/include) include_directories(/usr/local/opt/qt5/include /usr/local/include)
elseif (${TARGET_PLATFORM} STREQUAL "w64") elseif (${TARGET_PLATFORM} STREQUAL "w64")
set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp)
elseif (UNIX)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake")
endif () endif ()
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
find_package(Qt5WebKit REQUIRED)
find_package(Qt5WebKitWidgets REQUIRED)
qt5_wrap_ui(ui_Main.h Main.ui) qt5_wrap_ui(ui_Main.h Main.ui)
# Set name of binary and add_executable() # Set name of binary and add_executable()
@ -49,7 +53,7 @@ else ()
add_executable(${EXECUTEABLE} Main.ui ${SRC_LIST}) add_executable(${EXECUTEABLE} Main.ui ${SRC_LIST})
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core Gui Widgets Network) qt5_use_modules(${EXECUTEABLE} Core Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} ethereum secp256k1 ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTEABLE} ethereum secp256k1 ${CRYPTOPP_LIBRARIES})
if (APPLE) if (APPLE)
@ -95,6 +99,7 @@ elseif (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(${EXECUTEABLE} crypt32) target_link_libraries(${EXECUTEABLE} crypt32)
target_link_libraries(${EXECUTEABLE} Qt5PlatformSupport) target_link_libraries(${EXECUTEABLE} Qt5PlatformSupport)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else () else ()
target_link_libraries(${EXECUTEABLE} boost_system) target_link_libraries(${EXECUTEABLE} boost_system)
target_link_libraries(${EXECUTEABLE} boost_filesystem) target_link_libraries(${EXECUTEABLE} boost_filesystem)

168
alethzero/Main.ui

@ -36,9 +36,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QWidget" name="widget" native="true"/>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<item> <item>
@ -390,19 +387,22 @@
</attribute> </attribute>
<widget class="QWidget" name="dockWidgetContents_5"> <widget class="QWidget" name="dockWidgetContents_5">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label5"> <widget class="QLabel" name="label_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;To</string> <string>&amp;Data</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>destination</cstring> <cstring>data</cstring>
</property> </property>
</widget> </widget>
</item> </item>
@ -416,65 +416,126 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="3">
<widget class="QLabel" name="label_2"> <widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label5">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Data</string> <string>&amp;To</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>data</cstring> <cstring>destination</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="4"> <item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5"> <widget class="QSplitter" name="splitter_5">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<widget class="QPlainTextEdit" name="data"/> <widget class="QPlainTextEdit" name="data"/>
<widget class="QPlainTextEdit" name="code"> <widget class="QTextEdit" name="code">
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget> </widget>
</widget> </widget>
</item> </item>
<item row="5" column="3"> <item row="3" column="2">
<widget class="QPushButton" name="send"> <widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
<string> gas</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>&amp;Send</string> <string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="2"> <item row="4" column="1" colspan="3">
<widget class="QLabel" name="total"> <widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3"> <item row="6" column="3">
<widget class="QLineEdit" name="destination"> <widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Send</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QLabel" name="total">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>1</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="placeholderText"> <property name="text">
<string>(Create Contract)</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
@ -491,29 +552,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="0" column="1" colspan="3">
<widget class="QComboBox" name="valueUnits"/> <widget class="QLineEdit" name="destination">
</item> <property name="sizePolicy">
<item row="3" column="1" colspan="3"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<widget class="QLabel" name="fee"> <horstretch>1</horstretch>
<property name="text"> <verstretch>0</verstretch>
<string/> </sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property> </property>
<property name="value"> <property name="placeholderText">
<number>1000</number> <string>(Create Contract)</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -704,7 +752,7 @@
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_9"> <widget class="QDockWidget" name="configDock">
<property name="features"> <property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set> <set>QDockWidget::DockWidgetFeatureMask</set>
</property> </property>
@ -803,18 +851,16 @@
<tabstop>calculatedName</tabstop> <tabstop>calculatedName</tabstop>
<tabstop>value</tabstop> <tabstop>value</tabstop>
<tabstop>valueUnits</tabstop> <tabstop>valueUnits</tabstop>
<tabstop>gas</tabstop>
<tabstop>gasPrice</tabstop>
<tabstop>gasPriceUnits</tabstop>
<tabstop>data</tabstop> <tabstop>data</tabstop>
<tabstop>code</tabstop>
<tabstop>send</tabstop> <tabstop>send</tabstop>
<tabstop>idealPeers</tabstop> <tabstop>idealPeers</tabstop>
<tabstop>port</tabstop> <tabstop>port</tabstop>
<tabstop>clientName</tabstop> <tabstop>clientName</tabstop>
<tabstop>nameReg</tabstop>
<tabstop>verbosity</tabstop> <tabstop>verbosity</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>accounts</tabstop>
<tabstop>peers</tabstop>
<tabstop>log</tabstop>
<tabstop>ourAccounts</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>

301
alethzero/MainWin.cpp

@ -1,11 +1,14 @@
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog> #include <QtWidgets/QInputDialog>
#include <QtWebKitWidgets/QWebFrame>
#include <QtGui/QClipboard> #include <QtGui/QClipboard>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <libethereum/Dagger.h> #include <libethereum/Dagger.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Instruction.h> #include <libethereum/Instruction.h>
#include <libethereum/PeerServer.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
@ -30,12 +33,14 @@ using eth::Secret;
using eth::Transaction; using eth::Transaction;
// functions // functions
using eth::asHex; using eth::toHex;
using eth::assemble; using eth::assemble;
using eth::compileLisp; using eth::compileLisp;
using eth::disassemble; using eth::disassemble;
using eth::formatBalance; using eth::formatBalance;
using eth::fromUserHex; using eth::fromHex;
using eth::sha3;
using eth::left160;
using eth::right160; using eth::right160;
using eth::simpleDebugOut; using eth::simpleDebugOut;
using eth::toLog2; using eth::toLog2;
@ -51,9 +56,33 @@ static void initUnits(QComboBox* _b)
{ {
for (auto n = (::uint)units().size(); n-- != 0; ) for (auto n = (::uint)units().size(); n-- != 0; )
_b->addItem(QString::fromStdString(units()[n].second), n); _b->addItem(QString::fromStdString(units()[n].second), n);
_b->setCurrentIndex(6);
} }
string htmlDump(bytes const& _b, unsigned _w = 8)
{
stringstream ret;
ret << "<pre>";
for (unsigned i = 0; i < _b.size(); i += _w)
{
ret << hex << setw(4) << setfill('0') << i << " ";
for (unsigned j = i; j < i + _w; ++j)
if (j < _b.size())
if (_b[j] >= 32 && _b[j] < 128)
ret << (char)_b[j];
else ret << '?';
else
ret << ' ';
ret << " ";
for (unsigned j = i; j < i + _w && j < _b.size(); ++j)
ret << setfill('0') << setw(2) << hex << (unsigned)_b[j] << " ";
ret << "\n";
}
ret << "</pre>";
return ret.str();
}
Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250");
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::Main) ui(new Ui::Main)
@ -63,47 +92,6 @@ Main::Main(QWidget *parent) :
g_logPost = [=](std::string const& s, char const* c) { simpleDebugOut(s, c); ui->log->addItem(QString::fromStdString(s)); }; g_logPost = [=](std::string const& s, char const* c) { simpleDebugOut(s, c); ui->log->addItem(QString::fromStdString(s)); };
m_client.reset(new Client("AlethZero")); m_client.reset(new Client("AlethZero"));
/*
ui->librariesView->setModel(m_libraryMan);
ui->graphsView->setModel(m_graphMan);
setWindowIcon(QIcon(":/Noted.png"));
qmlRegisterSingletonType<TimeHelper>("com.llr", 1, 0, "Time", TimelineItem::constructTimeHelper);
qmlRegisterType<GraphItem>("com.llr", 1, 0, "Graph");
qmlRegisterType<CursorGraphItem>("com.llr", 1, 0, "CursorGraph");
qmlRegisterType<IntervalItem>("com.llr", 1, 0, "Interval");
qmlRegisterType<CursorItem>("com.llr", 1, 0, "Cursor");
qmlRegisterType<TimelinesItem>("com.llr", 1, 0, "Timelines");
qmlRegisterType<TimeLabelsItem>("com.llr", 1, 0, "TimeLabels");
qmlRegisterType<XLabelsItem>("com.llr", 1, 0, "XLabels");
qmlRegisterType<XScaleItem>("com.llr", 1, 0, "XScale");
qmlRegisterType<YLabelsItem>("com.llr", 1, 0, "YLabels");
qmlRegisterType<YScaleItem>("com.llr", 1, 0, "YScale");
m_view = new QQuickView();
QQmlContext* context = m_view->rootContext();
context->setContextProperty("libs", libs());
context->setContextProperty("compute", compute());
context->setContextProperty("data", data());
context->setContextProperty("graphs", graphs());
context->setContextProperty("audio", audio());
context->setContextProperty("view", view());
m_view->setSource(QUrl("qrc:/Noted.qml"));
QWidget* w = QWidget::createWindowContainer(m_view);
w->setAcceptDrops(true);
m_view->setResizeMode(QQuickView::SizeRootObjectToView);
ui->fullDisplay->insertWidget(0, w);
m_view->create();
m_timelinesItem = m_view->rootObject()->findChild<TimelinesItem*>("timelines");
qDebug() << m_view->rootObject();
*/
readSettings();
refresh();
m_refresh = new QTimer(this); m_refresh = new QTimer(this);
connect(m_refresh, SIGNAL(timeout()), SLOT(refresh())); connect(m_refresh, SIGNAL(timeout()), SLOT(refresh()));
m_refresh->start(100); m_refresh->start(100);
@ -119,6 +107,8 @@ Main::Main(QWidget *parent) :
int pocnumber = QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1).toInt(); int pocnumber = QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1).toInt();
if (pocnumber == 3) if (pocnumber == 3)
m_servers.push_back("54.201.28.117:30303"); m_servers.push_back("54.201.28.117:30303");
else if (pocnumber == 4)
m_servers.push_back("54.72.31.55:30303");
else else
{ {
connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r) connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r)
@ -132,13 +122,31 @@ Main::Main(QWidget *parent) :
} }
#endif #endif
ui->configDock->close();
on_verbosity_sliderMoved(); on_verbosity_sliderMoved();
initUnits(ui->gasPriceUnits);
initUnits(ui->valueUnits); initUnits(ui->valueUnits);
ui->valueUnits->setCurrentIndex(6);
ui->gasPriceUnits->setCurrentIndex(4);
ui->gasPrice->setValue(10);
on_destination_textChanged(); on_destination_textChanged();
statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount); statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->blockCount); statusBar()->addPermanentWidget(ui->blockCount);
readSettings();
refresh();
{
QSettings s("ethereum", "alethzero");
if (s.value("splashMessage", true).toBool())
{
QMessageBox::information(this, "Here Be Dragons!", "This is proof-of-concept software. The project as a whole is not even at the alpha-testing stage. It here to show you, if you have a technical bent, the sort of thing that might be possible down the line.\nPlease don't blame us if it does something unexpected or if you're underwhelmed with the user-experience. We have great plans for it in terms of UX down the line but right now we just want to get the groundwork sorted. We welcome contributions, be they in code, testing or documentation!\nAfter you close this message it won't appear again.");
s.setValue("splashMessage", false);
}
}
} }
Main::~Main() Main::~Main()
@ -149,7 +157,15 @@ Main::~Main()
QString Main::pretty(eth::Address _a) const QString Main::pretty(eth::Address _a) const
{ {
if (h256 n = state().contractMemory(m_nameReg, (h256)(u256)(u160)_a)) h256 n;
if (h160 nameReg = (u160)state().contractStorage(c_config, 0))
n = state().contractStorage(nameReg, (u160)(_a));
if (!n)
n = state().contractStorage(m_nameReg, (u160)(_a));
if (n)
{ {
std::string s((char const*)n.data(), 32); std::string s((char const*)n.data(), 32);
if (s.find_first_of('\0') != string::npos) if (s.find_first_of('\0') != string::npos)
@ -176,10 +192,16 @@ Address Main::fromString(QString const& _a) const
memcpy(n.data(), sn.data(), sn.size()); memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size()); memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size()) if (_a.size())
if (h256 a = state().contractMemory(m_nameReg, n)) {
if (h160 nameReg = (u160)state().contractStorage(c_config, 0))
if (h256 a = state().contractStorage(nameReg, n))
return right160(a);
if (h256 a = state().contractStorage(m_nameReg, n))
return right160(a); return right160(a);
}
if (_a.size() == 40) if (_a.size() == 40)
return Address(fromUserHex(_a.toStdString())); return Address(fromHex(_a.toStdString()));
else else
return Address(); return Address();
} }
@ -246,10 +268,7 @@ void Main::readSettings()
ui->clientName->setText(s.value("clientName", "").toString()); ui->clientName->setText(s.value("clientName", "").toString());
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt()); ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt());
if (s.value("nameReg").toString() == "11f62328e131dbb05ce4c73a3de3c7ab1c84a163") ui->nameReg->setText(s.value("NameReg", "").toString());
s.remove("nameReg");
ui->nameReg->setText(s.value("nameReg", "8ff91e5b145a23ab1afef34f12587c18bd42aec0").toString());
} }
void Main::on_nameReg_textChanged() void Main::on_nameReg_textChanged()
@ -257,9 +276,11 @@ void Main::on_nameReg_textChanged()
string s = ui->nameReg->text().toStdString(); string s = ui->nameReg->text().toStdString();
if (s.size() == 40) if (s.size() == 40)
{ {
m_nameReg = Address(fromUserHex(s)); m_nameReg = Address(fromHex(s));
refresh(true); refresh(true);
} }
else
m_nameReg = Address();
} }
void Main::refreshNetwork() void Main::refreshNetwork()
@ -319,7 +340,7 @@ void Main::refresh(bool _override)
QString("%2 +> %3: %1 [%4]") QString("%2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str()) .arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
.arg(render(right160(t.sha3()))) .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce)))))
.arg((unsigned)t.nonce); .arg((unsigned)t.nonce);
ui->transactionQueue->addItem(s); ui->transactionQueue->addItem(s);
} }
@ -345,7 +366,7 @@ void Main::refresh(bool _override)
QString(" %2 +> %3: %1 [%4]") QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str()) .arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
.arg(render(right160(t.sha3()))) .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce)))))
.arg((unsigned)t.nonce); .arg((unsigned)t.nonce);
QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks); QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks);
txItem->setData(Qt::UserRole, QByteArray((char const*)h.data(), h.size)); txItem->setData(Qt::UserRole, QByteArray((char const*)h.data(), h.size));
@ -360,14 +381,19 @@ void Main::refresh(bool _override)
m_keysChanged = false; m_keysChanged = false;
ui->ourAccounts->clear(); ui->ourAccounts->clear();
u256 totalBalance = 0; u256 totalBalance = 0;
u256 totalGavCoinBalance = 0;
Address gavCoin("91a10664d0cd489085a7a018beb5245d4f2272f1");
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
u256 b = st.balance(i.address()); u256 b = st.balance(i.address());
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)st.transactionsFrom(i.address())), ui->ourAccounts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)st.transactionsFrom(i.address())), ui->ourAccounts))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
totalBalance += b; totalBalance += b;
totalGavCoinBalance += st.contractStorage(gavCoin, (u160)i.address());
} }
ui->balance->setText(QString::fromStdString(formatBalance(totalBalance)));
ui->balance->setText(QString::fromStdString(toString(totalGavCoinBalance) + " GAV | " + formatBalance(totalBalance)));
} }
m_client->unlock(); m_client->unlock();
} }
@ -422,23 +448,30 @@ void Main::on_blocks_currentItemChanged()
{ {
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
Transaction tx(block[1][txi].data()); Transaction tx(block[1][txi].data());
h256 th = tx.sha3(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce));
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>"; s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
auto ss = tx.safeSender();
s << "<br/>From: <b>" << pretty(ss).toStdString() << "</b> " << ss; s << "<br/>From: <b>" << pretty(ss).toStdString() << "</b> " << ss;
if (tx.receiveAddress) if (tx.isCreation())
s << "<br/>To: <b>" << pretty(tx.receiveAddress).toStdString() << "</b> " << tx.receiveAddress;
else
s << "<br/>Creates: <b>" << pretty(right160(th)).toStdString() << "</b> " << right160(th); s << "<br/>Creates: <b>" << pretty(right160(th)).toStdString() << "</b> " << right160(th);
else
s << "<br/>To: <b>" << pretty(tx.receiveAddress).toStdString() << "</b> " << tx.receiveAddress;
s << "<br/>Value: <b>" << formatBalance(tx.value) << "</b>"; s << "<br/>Value: <b>" << formatBalance(tx.value) << "</b>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>"; s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>";
if (tx.data.size()) s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice) << "</b>";
s << "<br/>Gas: <b>" << tx.gas << "</b>";
if (tx.isCreation())
{ {
s << "<br/>Data:&nbsp;&emsp;&nbsp;"; if (tx.init.size())
// for (auto i: tx.data) s << "<h4>Init</h4>" << disassemble(tx.init);
// s << "0x<b>" << hex << i << "</b>&emsp;"; if (tx.data.size())
s << "</br>" << disassemble(tx.data); s << "<h4>Body</h4>" << disassemble(tx.data);
}
else
{
if (tx.data.size())
s << htmlDump(tx.data, 16);
} }
} }
@ -459,43 +492,10 @@ void Main::on_contracts_currentItemChanged()
auto h = h160((byte const*)hba.data(), h160::ConstructFromPointer); auto h = h160((byte const*)hba.data(), h160::ConstructFromPointer);
stringstream s; stringstream s;
auto mem = state().contractMemory(h); auto mem = state().contractStorage(h);
u256 next = 0; for (auto const& i: mem)
unsigned numerics = 0; s << "@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << i.second << "<br/>";
bool unexpectedNumeric = false; s << "<h4>Body Code</h4>" << disassemble(state().contractCode(h));
for (auto i: mem)
{
if (next < i.first)
{
unsigned j;
for (j = 0; j <= numerics && next + j < i.first; ++j)
s << (j < numerics || unexpectedNumeric ? " 0" : " <b>STOP</b>");
unexpectedNumeric = false;
numerics -= min(numerics, j);
if (next + j < i.first)
s << " ...<br/>@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;";
}
else if (!next)
{
s << "@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;";
}
auto iit = c_instructionInfo.find((Instruction)(unsigned)i.second);
if (numerics || iit == c_instructionInfo.end() || (u256)(unsigned)iit->first != i.second) // not an instruction or expecting an argument...
{
if (numerics)
numerics--;
else
unexpectedNumeric = true;
s << " " << showbase << hex << i.second;
}
else
{
auto const& ii = iit->second;
s << " <b>" << ii.name << "</b>";
numerics = ii.additional;
}
next = i.first + 1;
}
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
} }
m_client->unlock(); m_client->unlock();
@ -511,7 +511,7 @@ void Main::on_ourAccounts_doubleClicked()
{ {
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_log_doubleClicked() void Main::on_log_doubleClicked()
@ -523,14 +523,14 @@ void Main::on_accounts_doubleClicked()
{ {
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_contracts_doubleClicked() void Main::on_contracts_doubleClicked()
{ {
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_destination_textChanged() void Main::on_destination_textChanged()
@ -542,27 +542,98 @@ void Main::on_destination_textChanged()
ui->calculatedName->setText("Unknown Address"); ui->calculatedName->setText("Unknown Address");
else else
ui->calculatedName->setText("Create Contract"); ui->calculatedName->setText("Create Contract");
updateFee(); on_data_textChanged();
// updateFee();
} }
void Main::on_data_textChanged() void Main::on_data_textChanged()
{ {
string code = ui->data->toPlainText().toStdString(); if (isCreation())
m_data = code[0] == '(' ? compileLisp(code, true) : assemble(code, true); {
ui->code->setPlainText(QString::fromStdString(disassemble(m_data))); string code = ui->data->toPlainText().toStdString();
m_init.clear();
m_data = compileLisp(code, true, m_init);
ui->code->setHtml((m_init.size() ? "<h4>Init</h4>" + QString::fromStdString(disassemble(m_init)).toHtmlEscaped() : "") + "<h4>Body</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped());
ui->gas->setMinimum((qint64)state().createGas(m_data.size() + m_init.size(), 0));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
m_data.clear();
QString s = ui->data->toPlainText();
while (s.size())
{
QRegExp r("@?\"(.*)\"(.*)");
QRegExp h("@?(0x)?(([a-fA-F0-9][a-fA-F0-9])+)(.*)");
if (r.exactMatch(s))
{
for (auto i: r.cap(1))
m_data.push_back((byte)i.toLatin1());
if (s[0] == '@')
for (int i = r.cap(1).size(); i < 32; ++i)
m_data.push_back(0);
else
m_data.push_back(0);
s = r.cap(2);
}
else if (h.exactMatch(s))
{
bytes bs = fromHex(h.cap(2).toStdString());
if (s[0] == '@')
for (auto i = bs.size(); i < 32; ++i)
m_data.push_back(0);
for (auto b: bs)
m_data.push_back(b);
s = h.cap(4);
}
else
s = s.mid(1);
}
ui->code->setHtml(QString::fromStdString(htmlDump(m_data)));
if (m_client->postState().isContractAddress(fromString(ui->destination->text())))
{
ui->gas->setMinimum((qint64)state().callGas(m_data.size(), 1));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)state().callGas(m_data.size()));
ui->gas->setEnabled(false);
}
}
updateFee(); updateFee();
} }
bool Main::isCreation() const
{
return ui->destination->text().isEmpty()/* || !ui->destination->text().toInt()*/;
}
u256 Main::fee() const u256 Main::fee() const
{ {
return (ui->destination->text().isEmpty() || !ui->destination->text().toInt()) ? state().fee(m_data.size()) : state().fee(); return ui->gas->value() * gasPrice();
} }
u256 Main::value() const u256 Main::value() const
{ {
if (ui->valueUnits->currentIndex() == -1)
return 0;
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first; return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
} }
u256 Main::gasPrice() const
{
if (ui->gasPriceUnits->currentIndex() == -1)
return 0;
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first;
}
u256 Main::total() const u256 Main::total() const
{ {
return value() + fee(); return value() + fee();
@ -570,7 +641,7 @@ u256 Main::total() const
void Main::updateFee() void Main::updateFee()
{ {
ui->fee->setText(QString("(fee: %1)").arg(formatBalance(fee()).c_str())); ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total(); auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
@ -644,12 +715,14 @@ void Main::on_send_clicked()
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
m_client->lock(); m_client->lock();
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq ) if (m_client->state().balance(i.address()) >= totalReq)
{ {
m_client->unlock(); m_client->unlock();
Secret s = i.secret(); Secret s = i.secret();
Address r = fromString(ui->destination->text()); if (isCreation())
m_client->transact(s, r, value(), m_data); m_client->transact(s, value(), m_data, m_init, ui->gas->value(), gasPrice());
else
m_client->transact(s, value(), fromString(ui->destination->text()), m_data, ui->gas->value(), gasPrice());
refresh(); refresh();
return; return;
} }

23
alethzero/MainWin.h

@ -5,7 +5,7 @@
#include <QtCore/QAbstractListModel> #include <QtCore/QAbstractListModel>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <libethereum/Common.h> #include <libethereum/CommonEth.h>
namespace Ui { namespace Ui {
class Main; class Main;
@ -16,6 +16,13 @@ class Client;
class State; class State;
} }
class QQuickView;
class QQmlEngine;
class QJSEngine;
class QEthereum;
class QAccount;
class Main : public QMainWindow class Main : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
@ -23,6 +30,10 @@ class Main : public QMainWindow
public: public:
explicit Main(QWidget *parent = 0); explicit Main(QWidget *parent = 0);
~Main(); ~Main();
eth::Client* client() { return m_client.get(); }
QVector<eth::KeyPair> const& owned() const { return m_myKeys; }
private slots: private slots:
void on_connect_triggered(); void on_connect_triggered();
@ -38,7 +49,10 @@ private slots:
void on_data_textChanged(); void on_data_textChanged();
void on_idealPeers_valueChanged(); void on_idealPeers_valueChanged();
void on_value_valueChanged() { updateFee(); } void on_value_valueChanged() { updateFee(); }
void on_gas_valueChanged() { updateFee(); }
void on_valueUnits_currentIndexChanged() { updateFee(); } void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_gasPriceUnits_currentIndexChanged() { updateFee(); }
void on_gasPrice_valueChanged() { updateFee(); }
void on_log_doubleClicked(); void on_log_doubleClicked();
void on_blocks_currentItemChanged(); void on_blocks_currentItemChanged();
void on_contracts_doubleClicked(); void on_contracts_doubleClicked();
@ -63,9 +77,11 @@ private:
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();
bool isCreation() const;
eth::u256 fee() const; eth::u256 fee() const;
eth::u256 total() const; eth::u256 total() const;
eth::u256 value() const; eth::u256 value() const;
eth::u256 gasPrice() const;
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
@ -78,9 +94,12 @@ private:
QStringList m_servers; QStringList m_servers;
QVector<eth::KeyPair> m_myKeys; QVector<eth::KeyPair> m_myKeys;
bool m_keysChanged = false; bool m_keysChanged = false;
eth::u256s m_data; eth::bytes m_data;
eth::bytes m_init;
eth::Address m_nameReg; eth::Address m_nameReg;
unsigned m_backupGas;
QNetworkAccessManager m_webCtrl; QNetworkAccessManager m_webCtrl;
}; };

6
debian/README.Debian

@ -1,6 +0,0 @@
cpp-ethereum for Debian
-----------------------
<possible notes regarding this package - if none, delete this file>
-- Gav <Gav Wood <i@gavwood.com>> Mon, 03 Feb 2014 14:50:20 +0000

9
debian/README.source

@ -1,9 +0,0 @@
cpp-ethereum for Debian
-----------------------
<this file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file>

23
debian/changelog

@ -1,23 +0,0 @@
cpp-ethereum (0.1.0-1) saucy; urgency=low
* Various improvements moving towards PoC-2.
-- Ethereum (Ethereum Project) <ethereum@gavwood.com> Fri, 07 Feb 2014 00:48:26 +0000
cpp-ethereum (0.1-3) saucy; urgency=low
* Packaging stuff.
-- Ethereum (Ethereum Project) <ethereum@gavwood.com> Thu, 06 Feb 2014 14:13:00 +0000
cpp-ethereum (0.1-2) saucy; urgency=low
* Fix Qt dep.
-- Gav Wood <ethereum@gavwood.com> Mon, 06 Feb 2014 11:35:20 +0000
cpp-ethereum (0.1-1) saucy; urgency=low
* Initial release.
-- Gav Wood <ethereum@gavwood.com> Mon, 03 Feb 2014 14:50:20 +0000

1
debian/compat

@ -1 +0,0 @@
8

29
debian/control

@ -1,29 +0,0 @@
Source: cpp-ethereum
Section: science
Priority: extra
Maintainer: Ethereum (Ethereum Project) <ethereum@gavwood.com>
Build-Depends: debhelper (>= 8.0.0), cmake, libgmp-dev, libboost-thread-dev, libcryptoppeth-dev, libboost-filesystem-dev, libboost-mpi-dev, libboost-dev, libleveldb-dev, libminiupnpc-dev, qtbase5-dev, qt5-default
Standards-Version: 3.9.4
Homepage: http://ethereum.org
#Vcs-Git: git://git.debian.org/collab-maint/cpp-ethereum.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/cpp-ethereum.git;a=summary
Package: libethereum
Section: libdevel
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: The future of computational social contracts.
A long description of libethereum.
Package: libethereum-dev
Section: libdevel
Architecture: any
Depends: libethereum (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}
Description: The future of computational social contracts. Dev Files.
A long description of libethereum. Dev Files.
Package: alethzero
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libethereum (= ${binary:Version})
Description: The Qt-based Ethereum GUI.
A long description of alethzero.

24
debian/copyright

@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: cpp-ethereum
Source: github.com/ethereum/cpp-ethereum
Files: *
Copyright: 2014 Gav Wood <i@gavwood.com>
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3
debian/docs

@ -1,3 +0,0 @@
CodingStandards.txt
README.md
TODO

36
debian/rules

@ -1,36 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
#
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
#
# Modified to make a template file for a multi-binary package with separated
# build-arch and build-indep targets by Bill Allombert 2001
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This has to be exported to make some magic below work.
export DH_OPTIONS
%:
dh $@
override_dh_auto_configure:
cmake -DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/libethereum-dev/usr .
override_dh_auto_build:
$(MAKE) -j8
override_dh_auto_install:
$(MAKE) install
# Move the libs over to the non-dev package.
mkdir -p $(CURDIR)/debian/libethereum/usr
mv $(CURDIR)/debian/libethereum-dev/usr/lib $(CURDIR)/debian/libethereum/usr/lib
mkdir -p $(CURDIR)/debian/alethzero/usr/bin
mv $(CURDIR)/debian/libethereum-dev/usr/bin/alethzero $(CURDIR)/debian/alethzero/usr/bin

48
eth-ncurses-cli/CMakeLists.txt

@ -0,0 +1,48 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
include_directories(../libethereum)
link_directories(../libethereum)
add_executable(eth ${SRC_LIST})
if (${TARGET_PLATFORM} STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(eth gcc)
target_link_libraries(eth gdi32)
target_link_libraries(eth ws2_32)
target_link_libraries(eth mswsock)
target_link_libraries(eth shlwapi)
target_link_libraries(eth iphlpapi)
target_link_libraries(eth cryptopp)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
target_link_libraries(eth boost_system-mt-s)
target_link_libraries(eth boost_filesystem-mt-s)
target_link_libraries(eth boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
else ()
target_link_libraries(eth ${CRYPTOPP_LIBRARIES})
target_link_libraries(eth boost_system)
target_link_libraries(eth boost_filesystem)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
find_package(Threads REQUIRED)
target_link_libraries(eth ${CMAKE_THREAD_LIBS_INIT})
endif ()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
include_directories(/usr/local/include)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
target_link_libraries(eth ethereum)
target_link_libraries(eth miniupnpc)
target_link_libraries(eth leveldb)
target_link_libraries(eth gmp)
install( TARGETS eth DESTINATION bin )

1109
eth-ncurses-cli/main.cpp

File diff suppressed because it is too large

4
eth/CMakeLists.txt

@ -16,14 +16,18 @@ if (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(eth shlwapi) target_link_libraries(eth shlwapi)
target_link_libraries(eth iphlpapi) target_link_libraries(eth iphlpapi)
target_link_libraries(eth cryptopp) target_link_libraries(eth cryptopp)
target_link_libraries(eth form)
target_link_libraries(eth boost_system-mt-s) target_link_libraries(eth boost_system-mt-s)
target_link_libraries(eth boost_filesystem-mt-s) target_link_libraries(eth boost_filesystem-mt-s)
target_link_libraries(eth boost_thread_win32-mt-s) target_link_libraries(eth boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
target_link_libraries(eth form)
else () else ()
target_link_libraries(eth ${CRYPTOPP_LIBRARIES}) target_link_libraries(eth ${CRYPTOPP_LIBRARIES})
target_link_libraries(eth boost_system) target_link_libraries(eth boost_system)
target_link_libraries(eth boost_filesystem) target_link_libraries(eth boost_filesystem)
target_link_libraries(eth form)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(eth ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(eth ${CMAKE_THREAD_LIBS_INIT})
endif () endif ()

161
eth/main.cpp

@ -23,15 +23,19 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
#include <iostream>
#include "Defaults.h" #include "Defaults.h"
#include "Client.h" #include "Client.h"
#include "PeerNetwork.h" #include "PeerNetwork.h"
#include "BlockChain.h" #include "BlockChain.h"
#include "State.h" #include "State.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "Instruction.h"
#include "BuildInfo.h" #include "BuildInfo.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
using eth::Instruction;
using eth::c_instructionInfo;
bool isTrue(std::string const& _m) bool isTrue(std::string const& _m)
{ {
@ -68,6 +72,32 @@ void help()
exit(0); exit(0);
} }
string credits(bool _interactive = false)
{
std::ostringstream ccout;
ccout
<< "Ethereum (++) " << ETH_QUOTED(ETH_VERSION) << endl
<< " Code by Gav Wood, (c) 2013, 2014." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
if (_interactive)
{
string vs = toString(ETH_QUOTED(ETH_VERSION));
vs = vs.substr(vs.find_first_of('.') + 1)[0];
int pocnumber = stoi(vs);
string m_servers;
if (pocnumber == 3)
m_servers = "54.201.28.117";
if (pocnumber == 4)
m_servers = "54.72.31.55";
ccout << "Type 'netstart 30303' to start networking" << endl;
ccout << "Type 'connect " << m_servers << " 30303' to connect" << endl;
ccout << "Type 'exit' to quit" << endl << endl;
}
return ccout.str();
}
void version() void version()
{ {
cout << "eth version " << ETH_QUOTED(ETH_VERSION) << endl; cout << "eth version " << ETH_QUOTED(ETH_VERSION) << endl;
@ -75,12 +105,30 @@ void version()
exit(0); exit(0);
} }
u256 c_minGasPrice = 10000000000000;
u256 c_minGas = 100;
Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250");
string pretty(h160 _a, eth::State _st)
{
string ns;
h256 n;
if (h160 nameReg = (u160)_st.contractStorage(c_config, 0))
n = _st.contractStorage(nameReg, (u160)(_a));
if (n)
{
std::string s((char const*)n.data(), 32);
if (s.find_first_of('\0') != string::npos)
s.resize(s.find_first_of('\0'));
ns = " " + s;
}
return ns;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
unsigned short listenPort = 30303; unsigned short listenPort = 30303;
string remoteHost; string remoteHost;
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
bool interactive = false;
string dbPath; string dbPath;
eth::uint mining = ~(eth::uint)0; eth::uint mining = ~(eth::uint)0;
NodeMode mode = NodeMode::Full; NodeMode mode = NodeMode::Full;
@ -138,11 +186,9 @@ int main(int argc, char** argv)
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i]; clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
coinbase = h160(fromUserHex(argv[++i])); coinbase = h160(fromHex(argv[++i]));
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromUserHex(argv[++i]))); us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "-i" || arg == "--interactive")
interactive = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i]; dbPath = argv[++i];
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc) else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
@ -188,102 +234,19 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
Client c("Ethereum(++)/" + clientName + "v" ETH_QUOTED(ETH_VERSION) "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath); Client c("Ethereum(++)/" + clientName + "v" ETH_QUOTED(ETH_VERSION) "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath);
cout << credits();
if (interactive)
{ cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
cout << "Ethereum (++)" << endl; c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
cout << " Code by Gav Wood, (c) 2013, 2014." << endl; eth::uint n = c.blockChain().details().number;
cout << " Based on a design by Vitalik Buterin." << endl << endl; if (mining)
c.startMining();
while (true) while (true)
{
cout << "> " << flush;
std::string cmd;
cin >> cmd;
if (cmd == "netstart")
{
eth::uint port;
cin >> port;
c.startNetwork((short)port);
}
else if (cmd == "connect")
{
string addr;
eth::uint port;
cin >> addr >> port;
c.connect(addr, (short)port);
}
else if (cmd == "netstop")
{
c.stopNetwork();
}
else if (cmd == "minestart")
{
c.startMining();
}
else if (cmd == "minestop")
{
c.stopMining();
}
else if (cmd == "address")
{
cout << endl;
cout << "Current address: " + asHex(us.address().asArray()) << endl;
cout << "===" << endl;
}
else if (cmd == "secret")
{
cout << endl;
cout << "Current secret: " + asHex(us.secret().asArray()) << endl;
cout << "===" << endl;
}
else if (cmd == "balance")
{
u256 balance = c.state().balance(us.address());
cout << endl;
cout << "Current balance: ";
cout << balance << endl;
cout << "===" << endl;
}
else if (cmd == "transact")
{
string sechex;
string rechex;
u256 amount;
cin >> sechex >> rechex >> amount;
Secret secret = h256(fromUserHex(sechex));
Address dest = h160(fromUserHex(rechex));
c.transact(secret, dest, amount);
}
else if (cmd == "send")
{
string rechex;
u256 amount;
cin >> rechex >> amount;
Address dest = h160(fromUserHex(rechex));
c.transact(us.secret(), dest, amount);
}
else if (cmd == "exit")
{
break;
}
}
}
else
{ {
cout << "Address: " << endl << asHex(us.address().asArray()) << endl; if (c.blockChain().details().number - n == mining)
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); c.stopMining();
eth::uint n = c.blockChain().details().number; this_thread::sleep_for(chrono::milliseconds(100));
if (mining)
c.startMining();
while (true)
{
if (c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
} }
return 0; return 0;
} }

8
libethereum/AddressState.cpp

@ -20,6 +20,14 @@
*/ */
#include "AddressState.h" #include "AddressState.h"
#include "CommonEth.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
AddressState::AddressState(u256 _balance, u256 _nonce, bytesConstRef _code):
m_type(AddressType::Contract),
m_balance(_balance),
m_nonce(_nonce),
m_isComplete(true),
m_code(_code.toBytes())
{}

39
libethereum/AddressState.h

@ -37,24 +37,10 @@ enum class AddressType
class AddressState class AddressState
{ {
public: public:
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_haveMemory(false) {} AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_isComplete(false) {}
AddressState(u256 _balance, u256 _nonce, AddressType _type = AddressType::Normal): m_type(_type), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true) {} AddressState(u256 _balance, u256 _nonce, AddressType _type = AddressType::Normal): m_type(_type), m_balance(_balance), m_nonce(_nonce), m_isComplete(true) {}
AddressState(u256 _balance, u256 _nonce, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(false), m_contractRoot(_contractRoot) {} AddressState(u256 _balance, u256 _nonce, h256 _contractRoot, h256 _codeHash): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_isComplete(false), m_contractRoot(_contractRoot), m_codeHash(_codeHash) {}
AddressState(u256 _balance, u256 _nonce, u256s _memory): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true) AddressState(u256 _balance, u256 _nonce, bytesConstRef _code);
{
for (unsigned i = 0; i < _memory.size(); ++i)
#ifdef __clang__
{
auto mFinder = m_memory.find((u256)i);
if (mFinder == m_memory.end())
m_memory.insert(std::make_pair((u256)i,_memory[i]));
else
mFinder->second = _memory[i];
}
#else
m_memory[(u256)i] = _memory[i];
#endif
}
void incNonce() { m_nonce++; } void incNonce() { m_nonce++; }
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); } void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
@ -65,20 +51,25 @@ public:
u256 const& balance() const { return m_balance; } u256 const& balance() const { return m_balance; }
u256& nonce() { return m_nonce; } u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; } u256 const& nonce() const { return m_nonce; }
bool haveMemory() const { return m_haveMemory; } bool isComplete() const { return m_isComplete; }
std::map<u256, u256>& setHaveMemory() { assert(m_type == AddressType::Contract); m_haveMemory = true; m_contractRoot = h256(); return m_memory; } std::map<u256, u256>& setIsComplete(bytesConstRef _code) { assert(m_type == AddressType::Contract); m_isComplete = true; m_contractRoot = h256(); m_code = _code.toBytes(); return m_memory; }
h256 oldRoot() const { assert(!haveMemory()); return m_contractRoot; } h256 oldRoot() const { assert(!isComplete()); return m_contractRoot; }
std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; } h256 codeHash() const { assert(m_codeHash); return m_codeHash; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; } std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
bytes const& code() const { assert(m_type == AddressType::Contract && isComplete()); return m_code; }
bool freshCode() const { return !m_codeHash && m_isComplete; }
private: private:
AddressType m_type; AddressType m_type;
u256 m_balance; u256 m_balance;
u256 m_nonce; u256 m_nonce;
bool m_haveMemory; bool m_isComplete;
h256 m_contractRoot; h256 m_contractRoot;
h256 m_codeHash; // if 0 and m_isComplete, has been created and needs to be inserted.
// TODO: change to unordered_map. // TODO: change to unordered_map.
std::map<u256, u256> m_memory; std::map<u256, u256> m_memory;
bytes m_code;
}; };
} }

4
libethereum/BlockChain.cpp

@ -45,7 +45,7 @@ std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc)
if (it->key().ToString() != "best") if (it->key().ToString() != "best")
{ {
BlockDetails d(RLP(it->value().ToString())); BlockDetails d(RLP(it->value().ToString()));
_out << asHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
} }
delete it; delete it;
return _out; return _out;
@ -221,7 +221,7 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
// This might be the new last block... // This might be the new best block...
if (td > details(m_lastBlockHash).totalDifficulty) if (td > details(m_lastBlockHash).totalDifficulty)
{ {
m_lastBlockHash = newHash; m_lastBlockHash = newHash;

3
libethereum/BlockChain.h

@ -22,7 +22,8 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include "Common.h" #include "CommonEth.h"
#include "Log.h"
#include "AddressState.h" #include "AddressState.h"
namespace ldb = leveldb; namespace ldb = leveldb;

13
libethereum/CMakeLists.txt

@ -10,7 +10,9 @@ if(APPLE)
else() else()
add_library(ethereum ${SRC_LIST}) add_library(ethereum ${SRC_LIST})
endif() endif()
if (UNIX)
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale)
endif()
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
include_directories(../secp256k1) include_directories(../secp256k1)
@ -39,6 +41,15 @@ elseif (APPLE)
target_link_libraries(ethereum boost_thread-mt) target_link_libraries(ethereum boost_thread-mt)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(ethereum ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(ethereum ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(ethereum ${CRYPTOPP_LIBRARIES})
target_link_libraries(ethereum ${Boost_SYSTEM_LIBRARY})
target_link_libraries(ethereum ${Boost_FILESYSTEM_LIBRARY})
target_link_libraries(ethereum ${Boost_THREAD_LIBRARY})
target_link_libraries(ethereum ${Boost_DATE_TIME_LIBRARY})
target_link_libraries(ethereum leveldb)
# target_link_libraries(ethereum snappy)
target_link_libraries(ethereum ${CMAKE_THREAD_LIBS_INIT})
else () else ()
target_link_libraries(ethereum ${CRYPTOPP_LIBRARIES}) target_link_libraries(ethereum ${CRYPTOPP_LIBRARIES})
target_link_libraries(ethereum boost_system) target_link_libraries(ethereum boost_system)

59
libethereum/Client.cpp

@ -26,6 +26,7 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "Common.h" #include "Common.h"
#include "Defaults.h" #include "Defaults.h"
#include "PeerServer.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -51,7 +52,7 @@ void VersionChecker::setOk()
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath): Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath):
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_vc(_dbPath, PeerSession::protocolVersion()), m_vc(_dbPath, PeerServer::protocolVersion()),
m_bc(_dbPath, !m_vc.ok()), m_bc(_dbPath, !m_vc.ok()),
m_stateDB(State::openDB(_dbPath, !m_vc.ok())), m_stateDB(State::openDB(_dbPath, !m_vc.ok())),
m_preMine(_us, m_stateDB), m_preMine(_us, m_stateDB),
@ -61,11 +62,6 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
m_vc.setOk(); m_vc.setOk();
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
m_preMine.sync(m_bc);
m_postMine = m_preMine;
m_changed = true; m_changed = true;
static const char* c_threadName = "eth"; static const char* c_threadName = "eth";
@ -75,6 +71,11 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
while (m_workState.load(std::memory_order_acquire) != Deleting) while (m_workState.load(std::memory_order_acquire) != Deleting)
work(); work();
m_workState.store(Deleted, std::memory_order_release); m_workState.store(Deleted, std::memory_order_release);
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
m_preMine.sync(m_bc);
m_postMine = m_preMine;
})); }));
} }
@ -91,12 +92,32 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
{ {
if (m_net.get()) if (m_net.get())
return; return;
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp)); try
{
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp));
}
catch (std::exception const&)
{
// Probably already have the port open.
cwarn << "Could not initialize with specified/default port. Trying system-assigned port";
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _mode, _publicIP, _upnp));
}
m_net->setIdealPeerCount(_peers); m_net->setIdealPeerCount(_peers);
if (_seedHost.size()) if (_seedHost.size())
connect(_seedHost, _port); connect(_seedHost, _port);
} }
std::vector<PeerInfo> Client::peers()
{
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
size_t Client::peerCount() const
{
return m_net ? m_net->peerCount() : 0;
}
void Client::connect(std::string const& _seedHost, unsigned short _port) void Client::connect(std::string const& _seedHost, unsigned short _port)
{ {
if (!m_net.get()) if (!m_net.get())
@ -120,13 +141,15 @@ void Client::stopMining()
m_doMine = false; m_doMine = false;
} }
void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data) void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
lock_guard<recursive_mutex> l(m_lock); lock_guard<recursive_mutex> l(m_lock);
Transaction t; Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = _dest; t.receiveAddress = _dest;
t.value = _amount;
t.data = _data; t.data = _data;
t.sign(_secret); t.sign(_secret);
cnote << "New transaction " << t; cnote << "New transaction " << t;
@ -134,6 +157,24 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data)
m_changed = true; m_changed = true;
} }
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _code, bytes const& _init, u256 _gas, u256 _gasPrice)
{
lock_guard<recursive_mutex> l(m_lock);
Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.value = _endowment;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = Address();
t.data = _code;
t.init = _init;
t.sign(_secret);
cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp());
m_changed = true;
return right160(sha3(rlpList(t.sender(), t.nonce)));
}
void Client::work() void Client::work()
{ {
bool changed = false; bool changed = false;

19
libethereum/Client.h

@ -83,8 +83,15 @@ public:
/// Destructor. /// Destructor.
~Client(); ~Client();
/// Executes the given transaction. /// Submits the given message-call transaction.
void transact(Secret _secret, Address _dest, u256 _amount, u256s _data = u256s()); void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
Address transact(Secret _secret, u256 _endowment, bytes const& _code, bytes const& _init = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Makes the given call. Nothing is recorded into the state. TODO
// bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());
/// Requires transactions involving this address be queued for inspection. /// Requires transactions involving this address be queued for inspection.
void setInterest(Address _dest); void setInterest(Address _dest);
@ -125,9 +132,9 @@ public:
// Network stuff: // Network stuff:
/// Get information on the current peer set. /// Get information on the current peer set.
std::vector<PeerInfo> peers() { return m_net ? m_net->peers() : std::vector<PeerInfo>(); } std::vector<PeerInfo> peers();
/// Same as peers().size(), but more efficient. /// Same as peers().size(), but more efficient.
size_t peerCount() const { return m_net ? m_net->peerCount() : 0; } size_t peerCount() const;
/// Start the network subsystem. /// Start the network subsystem.
void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true); void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true);
@ -135,6 +142,8 @@ public:
void connect(std::string const& _seedHost, unsigned short _port = 30303); void connect(std::string const& _seedHost, unsigned short _port = 30303);
/// Stop the network subsystem. /// Stop the network subsystem.
void stopNetwork(); void stopNetwork();
/// Is the network subsystem up?
bool haveNetwork() { return !!m_net; }
/// Get access to the peer server object. This will be null if the network isn't online. /// Get access to the peer server object. This will be null if the network isn't online.
PeerServer* peerServer() const { return m_net.get(); } PeerServer* peerServer() const { return m_net.get(); }
@ -148,6 +157,8 @@ public:
void startMining(); void startMining();
/// Stop mining. /// Stop mining.
void stopMining(); void stopMining();
/// Are we mining now?
bool isMining() { return m_doMine; }
/// Check the progress of the mining. /// Check the progress of the mining.
MineProgress miningProgress() const { return m_mineProgress; } MineProgress miningProgress() const { return m_mineProgress; }

280
libethereum/Common.cpp

@ -21,285 +21,5 @@
#include "Common.h" #include "Common.h"
#include <fstream>
#include <random>
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <secp256k1.h>
#include <sha3.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include "Exceptions.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
//#define ETH_ADDRESS_DEBUG 1
// Logging
int eth::g_logVerbosity = 8;
map<type_info const*, bool> eth::g_logOverride;
ThreadLocalLogName eth::t_logThreadName("main");
void eth::simpleDebugOut(std::string const& _s, char const*)
{
cout << _s << endl << flush;
}
std::function<void(std::string const&, char const*)> eth::g_logPost = simpleDebugOut;
std::string eth::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || i > 127 || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string eth::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int eth::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes eth::fromUserHex(std::string const& _s)
{
assert(_s.size() % 2 == 0);
if (_s.size() < 2)
return bytes();
uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s) / 2);
for (uint i = s; i < _s.size(); i += 2)
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
return ret;
}
bytes eth::toHex(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}
std::string eth::sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void eth::sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes eth::sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 eth::sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}
Address eth::toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << asHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
static const vector<pair<u256, string>> g_units =
{
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Uether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Vether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Dether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Nether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Yether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Zether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000000, "Eether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000, "Pether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000, "Tether"},
{(u256(1000000000) * 1000000000) * 1000000000, "Gether"},
{(u256(1000000000) * 1000000000) * 1000000, "Mether"},
{(u256(1000000000) * 1000000000) * 1000, "Kether"},
{u256(1000000000) * 1000000000, "ether"},
{u256(1000000000) * 1000000, "finney"},
{u256(1000000000) * 1000, "szabo"},
{u256(1000000000), "Gwei"},
{u256(1000000), "Mwei"},
{u256(1000), "Kwei"},
{u256(1), "wei"}
};
vector<pair<u256, string>> const& eth::units()
{
return g_units;
}
std::string eth::formatBalance(u256 _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
return ret.str();
}
bytes eth::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
void eth::writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

617
libethereum/Common.h

@ -18,13 +18,13 @@
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
* *
* Shared algorithms and data types. * Very common stuff (i.e. that every other header needs except vector_ref.h).
*/ */
#pragma once #pragma once
// define version // define version
#define ETH_VERSION 0.3.11 #define ETH_VERSION 0.4.3
// way to many uint to size_t warnings in 32 bit build // way to many uint to size_t warnings in 32 bit build
#ifdef _M_IX86 #ifdef _M_IX86
@ -36,27 +36,16 @@
#define noexcept throw() #define noexcept throw()
#endif #endif
#include <ctime>
#include <chrono>
#include <array>
#include <map> #include <map>
#include <unordered_map> #include <vector>
#include <set> #include <set>
#include <array>
#include <list>
#include <set>
#include <string>
#include <cassert>
#include <sstream>
#include <cstdint>
#include <type_traits>
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#include <boost/thread.hpp>
#include "vector_ref.h" #include "vector_ref.h"
// CryptoPP defines byte in the global namespace, so so must we. // CryptoPP defines byte in the global namespace, so so must we.
using byte = uint8_t; using byte = uint8_t;
// Quote a given token stream to turn it into a string.
#define ETH_QUOTED_HELPER(s) #s #define ETH_QUOTED_HELPER(s) #s
#define ETH_QUOTED(s) ETH_QUOTED_HELPER(s) #define ETH_QUOTED(s) ETH_QUOTED_HELPER(s)
@ -81,132 +70,6 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>; using u256Set = std::set<u256>;
using u160Set = std::set<u160>; using u160Set = std::set<u160>;
template <class T, class Out> inline void toBigEndian(T _val, Out& o_out);
template <class T, class In> inline T fromBigEndian(In const& _bytes);
/// 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.
/// @example asHex("A\x69") == "4169"
template <class _T>
std::string asHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromUserHex("41626261") == asBytes("Abba")
bytes fromUserHex(std::string const& _s);
template <unsigned T> class UnitTest {};
template <unsigned N>
class FixedHash
{
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
public:
enum { size = N };
enum ConstructFromPointerType { ConstructFromPointer };
FixedHash() { m_data.fill(0); }
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<uint>(_b.size(), N)); }
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
explicit FixedHash(std::string const& _user): FixedHash(fromUserHex(_user)) {}
operator Arith() const { return fromBigEndian<Arith>(m_data); }
operator bool() const { return ((Arith)*this) != 0; }
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; }
FixedHash& operator^=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; }
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
std::string abridged() const { return asHex(ref().cropped(0, 4)) + ".."; }
byte& operator[](unsigned _i) { return m_data[_i]; }
byte operator[](unsigned _i) const { return m_data[_i]; }
bytesRef ref() { return bytesRef(m_data.data(), N); }
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
byte* data() { return m_data.data(); }
byte const* data() const { return m_data.data(); }
bytes asBytes() const { return bytes(data(), data() + N); }
std::array<byte, N>& asArray() { return m_data; }
std::array<byte, N> const& asArray() const { return m_data; }
// generic std::hash compatible function object
struct hash
{
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << 5 - h) + i;
return h;
}
};
private:
std::array<byte, N> m_data;
};
// fast equality for h256
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
const uint64_t* hash1 = (const uint64_t*)this->data();
const uint64_t* hash2 = (const uint64_t*)_other.data();
return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
}
// fast std::hash compatible hash function object for h256
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
}
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::setw(2) << (int)_h[i];
_out << std::dec;
return _out;
}
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using Secret = h256;
using Public = h512;
using Address = h160;
using Addresses = h160s;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>; using u256Map = std::map<u256, u256>;
@ -216,475 +79,7 @@ using HexMap = std::map<bytes, std::string>;
static const u256 Invalid256 = ~(u256)0; static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes; static const bytes NullBytes;
/// Logging /// Trivial UnitTest type that everyone can agree on, mainly to allow befriending for test classes & their code.
class NullOutputStream template <unsigned T> class UnitTest {};
{
public:
template <class T> NullOutputStream& operator<<(T const&) { return *this; }
};
extern std::map<std::type_info const*, bool> g_logOverride;
struct ThreadLocalLogName
{
ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); };
boost::thread_specific_ptr<std::string> m_name;
};
extern ThreadLocalLogName t_logThreadName;
inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); }
struct LogChannel { static const char* name() { return " "; } static const int verbosity = 1; };
struct LeftChannel: public LogChannel { static const char* name() { return "<<<"; } };
struct RightChannel: public LogChannel { static const char* name() { return ">>>"; } };
struct WarnChannel: public LogChannel { static const char* name() { return "!!!"; } static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char* name() { return "***"; } };
struct DebugChannel: public LogChannel { static const char* name() { return "---"; } static const int verbosity = 0; };
extern int g_logVerbosity;
extern std::function<void(std::string const&, char const*)> g_logPost;
void simpleDebugOut(std::string const&, char const* );
template <class Id, bool _AutoSpacing = true>
class LogOutputStream
{
public:
LogOutputStream(bool _term = true)
{
std::type_info const* i = &typeid(Id);
auto it = g_logOverride.find(i);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && Id::verbosity <= g_logVerbosity))
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
sstr << Id::name() << " [ " << buf << " | " << *(t_logThreadName.m_name.get()) << (_term ? " ] " : "");
}
}
~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(sstr.str(), Id::name()); }
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && sstr.str().size() && sstr.str().back() != ' ') sstr << " "; sstr << _t; } return *this; }
std::stringstream sstr;
};
// Dirties the global namespace, but oh so convenient...
#define cnote eth::LogOutputStream<eth::NoteChannel, true>()
#define cwarn eth::LogOutputStream<eth::WarnChannel, true>()
#define ndebug if (true) {} else eth::NullOutputStream()
#define nlog(X) if (true) {} else eth::NullOutputStream()
#define nslog(X) if (true) {} else eth::NullOutputStream()
#if NDEBUG
#define cdebug ndebug
#else
#define cdebug eth::LogOutputStream<eth::DebugChannel, true>()
#endif
#if NLOG
#define clog(X) nlog(X)
#define cslog(X) nslog(X)
#else
#define clog(X) eth::LogOutputStream<X, true>()
#define cslog(X) eth::LogOutputStream<X, false>()
#endif
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
/// Converts byte array 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(bytes const& _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)
{
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>
void trimFront(_T& _t, uint _elements)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements);
}
/// Pushes an element on to the front of a collection.
/// Only works for POD element types.
template <class _T, class _U>
void pushFront(_T& _t, _U _e)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
_t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e;
}
/// Creates a random, printable, word.
std::string randomWord();
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
/// Converts a (printable) ASCII hex character into the correspnding integer value.
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
int fromHex(char _i);
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example toHex("A")[0] == 4 && toHex("A")[1] == 1
bytes toHex(std::string const& _s);
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
for (auto i = o_out.size(); i-- != 0; _val >>= 8)
o_out[i] = (typename _Out::value_type)(uint8_t)_val;
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
_T ret = 0;
for (auto i: _bytes)
ret = (ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i;
return ret;
}
/// Convenience functions for toBigEndian
inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; }
inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val.
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0');
toBigEndian(_val, ret);
return ret;
}
/// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U>
uint commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
for (uint i = 0;; ++i)
if (i == s || _t[i] != _u[i])
return i;
return s;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t)
{
h160 ret;
memcpy(ret.data(), _t.data() + 12, 20);
return ret;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the left 20 bytes.
inline h160 left160(h256 const& _t)
{
h160 ret;
memcpy(&ret[0], _t.data(), 20);
return ret;
}
/// Convert the given value into u160 (160-bit unsigned integer) by taking the lowest order 160-bits and discarding the rest.
inline u160 low160(u256 const& _t)
{
return (u160)(_t & ((((u256)1) << 160) - 1));
}
inline u160 low160(bigint const& _t)
{
return (u160)(_t & ((((bigint)1) << 160) - 1));
}
/// Convert the given value into u160 (160-bit unsigned integer) by taking the lowest order 160-bits and discarding the rest.
inline u160 high160(u256 const& _t)
{
return (u160)(_t >> 96);
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
/// SHA-3 convenience routines.
void sha3(bytesConstRef _input, bytesRef _output);
std::string sha3(std::string const& _input, bool _hex);
bytes sha3Bytes(bytesConstRef _input);
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
h256 sha3(bytesConstRef _input);
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
class KeyPair
{
public:
KeyPair() {}
KeyPair(Secret _k);
static KeyPair create();
Secret const& secret() const { return m_secret; }
Secret const& sec() const { return m_secret; }
Public const& pub() const { return m_public; }
Address const& address() const { return m_address; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
// Stream IO
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
for (auto i = ++_e.begin(); i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned long Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned long Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
inline S& streamout(S& _out, std::list<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
_out << _e.front();
for (auto i = ++_e.begin(); i != _e.end(); ++i)
_out << "," << *i;
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
inline S& streamout(S& _out, std::pair<T, U> const& _e)
{
_out << "(" << _e.first << "," << _e.second << ")";
return _out;
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T1, class T2, class T3>
inline S& streamout(S& _out, std::tuple<T1, T2, T3> const& _t)
{
_out << "(" << std::get<0>(_t) << "," << std::get<1>(_t) << "," << std::get<2>(_t) << ")";
return _out;
}
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::unordered_map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::multiset<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::multiset<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::multimap<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
T l;
int i = 0;
for (auto p: _v)
if (!(i++))
_out << "{ " << (l = p.first) << " => " << p.second;
else if (l == p.first)
_out << ", " << p.second;
else
_out << "; " << (l = p.first) << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
bytes contents(std::string const& _file);
void writeFile(std::string const& _file, bytes const& _data);
}
namespace std
{
// forward std::hash<eth::h256> to eth::h256::hash
template<> struct hash<eth::h256>: eth::h256::hash {};
} }

95
libethereum/CommonData.cpp

@ -0,0 +1,95 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonData.h"
#include <random>
#include "Exceptions.h"
using namespace std;
using namespace eth;
std::string eth::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string eth::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int eth::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes eth::fromHex(std::string const& _s)
{
if (_s.size() % 2 || _s.size() < 2)
return bytes();
uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s) / 2);
for (uint i = s; i < _s.size(); i += 2)
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
return ret;
}
bytes eth::asNibbles(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}

195
libethereum/CommonData.h

@ -0,0 +1,195 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Shared algorithms and data types.
*/
#pragma once
#include <vector>
#include <algorithm>
#include <type_traits>
#include <cstring>
#include <string>
#include "Common.h"
namespace eth
{
// String conversion functions, mainly to/from hex/nibble/byte representations.
/// 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.
/// @example toHex("A\x69") == "4169"
template <class _T>
std::string toHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
/// Converts a (printable) ASCII hex character into the correspnding integer value.
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
int fromHex(char _i);
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromHex("41626261") == asBytes("Abba")
bytes fromHex(std::string const& _s);
/// Converts byte array 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(bytes const& _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)
{
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles(std::string const& _s);
// Big-endian to/from host endian conversion functions.
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
for (auto i = o_out.size(); i-- != 0; _val >>= 8)
o_out[i] = (typename _Out::value_type)(uint8_t)_val;
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
_T ret = 0;
for (auto i: _bytes)
ret = (ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i;
return ret;
}
/// Convenience functions for toBigEndian
inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; }
inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val.
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0');
toBigEndian(_val, ret);
return ret;
}
// Algorithms for string and string-like collections.
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
/// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U>
uint commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
for (uint i = 0;; ++i)
if (i == s || _t[i] != _u[i])
return i;
return s;
}
/// Creates a random, printable, word.
std::string randomWord();
// General datatype convenience functions.
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T>
inline uint bytesRequired(_T _i)
{
uint i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>
void trimFront(_T& _t, uint _elements)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements);
}
/// Pushes an element on to the front of a collection.
/// Only works for POD element types.
template <class _T, class _U>
void pushFront(_T& _t, _U _e)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
_t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
}

189
libethereum/CommonEth.cpp

@ -0,0 +1,189 @@
/*
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 CommonEth.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonEth.h"
#include "CryptoHeaders.h"
#include "Exceptions.h"
#include <random>
using namespace std;
using namespace eth;
//#define ETH_ADDRESS_DEBUG 1
static const vector<pair<u256, string>> g_units =
{
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Uether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Vether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Dether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Nether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Yether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Zether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000000, "Eether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000, "Pether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000, "Tether"},
{(u256(1000000000) * 1000000000) * 1000000000, "Gether"},
{(u256(1000000000) * 1000000000) * 1000000, "Mether"},
{(u256(1000000000) * 1000000000) * 1000, "Kether"},
{u256(1000000000) * 1000000000, "ether"},
{u256(1000000000) * 1000000, "finney"},
{u256(1000000000) * 1000, "szabo"},
{u256(1000000000), "Gwei"},
{u256(1000000), "Mwei"},
{u256(1000), "Kwei"},
{u256(1), "wei"}
};
vector<pair<u256, string>> const& eth::units()
{
return g_units;
}
std::string eth::formatBalance(u256 _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
return ret.str();
}
Address eth::toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
std::string eth::sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void eth::sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes eth::sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 eth::sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}

137
libethereum/CommonEth.h

@ -0,0 +1,137 @@
/*
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 CommonEth.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include "Common.h"
#include "FixedHash.h"
namespace eth
{
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Secret = h256;
/// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Public = h512;
/// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();
// The various denominations; here for ease of use where needed within code.
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
class KeyPair
{
public:
/// Null constructor.
KeyPair() {}
/// Normal constructor - populates object from the given secret key.
KeyPair(Secret _k);
/// Create a new, randomly generated object.
static KeyPair create();
/// Retrieve the secret key.
Secret const& secret() const { return m_secret; }
/// Retrieve the secret key.
Secret const& sec() const { return m_secret; }
/// Retrieve the public key.
Public const& pub() const { return m_public; }
/// Retrieve the associated address of the public key.
Address const& address() const { return m_address; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
// SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input and load it into the given output.
void sha3(bytesConstRef _input, bytesRef _output);
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
std::string sha3(std::string const& _input, bool _isNibbles);
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
bytes sha3Bytes(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
}

48
libethereum/CommonIO.cpp

@ -0,0 +1,48 @@
/*
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 CommonIO.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Common.h"
#include <fstream>
#include "Exceptions.h"
using namespace std;
using namespace eth;
bytes eth::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
void eth::writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

223
libethereum/CommonIO.h

@ -0,0 +1,223 @@
/*
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 CommonIO.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* File & stream I/O routines.
*/
#pragma once
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <array>
#include <list>
#include <memory>
#include <vector>
#include <array>
#include <sstream>
#include <string>
#include <iostream>
#include "Common.h"
namespace eth
{
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
void writeFile(std::string const& _file, bytes const& _data);
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
// Stream I/O functions.
// Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface.
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
for (auto i = ++_e.begin(); i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned long Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned long Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
inline S& streamout(S& _out, std::list<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
_out << _e.front();
for (auto i = ++_e.begin(); i != _e.end(); ++i)
_out << "," << *i;
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
inline S& streamout(S& _out, std::pair<T, U> const& _e)
{
_out << "(" << _e.first << "," << _e.second << ")";
return _out;
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T1, class T2, class T3>
inline S& streamout(S& _out, std::tuple<T1, T2, T3> const& _t)
{
_out << "(" << std::get<0>(_t) << "," << std::get<1>(_t) << "," << std::get<2>(_t) << ")";
return _out;
}
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::unordered_map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::unordered_set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::unordered_set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::multiset<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::multiset<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::multimap<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
T l;
int i = 0;
for (auto p: _v)
if (!(i++))
_out << "{ " << (l = p.first) << " => " << p.second;
else if (l == p.first)
_out << ", " << p.second;
else
_out << "; " << (l = p.first) << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
}

36
libethereum/CryptoHeaders.h

@ -0,0 +1,36 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CryptoHeaders.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2014
*/
#pragma once
// need to leave this one disabled
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push)
#pragma warning(disable:4100 4244)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#include <secp256k1.h>
#pragma warning(pop)
#pragma GCC diagnostic pop

11
libethereum/Dagger.cpp

@ -22,17 +22,8 @@
#include <boost/detail/endian.hpp> #include <boost/detail/endian.hpp>
#include <chrono> #include <chrono>
#include <array> #include <array>
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <sha3.h>
#if WIN32
#pragma warning(pop)
#endif
#include <random> #include <random>
#include "CryptoHeaders.h"
#include "Common.h" #include "Common.h"
#include "Dagger.h" #include "Dagger.h"
using namespace std; using namespace std;

3
libethereum/Dagger.h

@ -23,7 +23,8 @@
#pragma once #pragma once
#include "Common.h" #include "FixedHash.h"
#include "CommonEth.h"
#define FAKE_DAGGER 1 #define FAKE_DAGGER 1

14
libethereum/Exceptions.h

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <exception> #include <exception>
#include "Common.h" #include "CommonIO.h"
#include "CommonData.h"
#include "FixedHash.h"
namespace eth namespace eth
{ {
@ -24,20 +26,22 @@ class VMException: public Exception {};
class StepsDone: public VMException {}; class StepsDone: public VMException {};
class BreakPointHit: public VMException {}; class BreakPointHit: public VMException {};
class BadInstruction: public VMException {}; class BadInstruction: public VMException {};
class OutOfGas: public VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; }; class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
class GasPriceTooLow: public Exception {};
class NoSuchContract: public Exception {}; class NoSuchContract: public Exception {};
class ContractAddressCollision: public Exception {}; class ContractAddressCollision: public Exception {};
class FeeTooSmall: public Exception {}; class FeeTooSmall: public Exception {};
class InvalidSignature: public Exception {}; class InvalidSignature: public Exception {};
class InvalidTransactionFormat: public Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + asHex(m_d) + ")"; } }; class InvalidTransactionFormat: public Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + asHex(m_d) + ")"; } }; class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + asHex(m_d) + ")"; } }; class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidUnclesHash: public Exception {}; class InvalidUnclesHash: public Exception {};
class InvalidUncle: public Exception {}; class InvalidUncle: public Exception {};
class InvalidStateRoot: public Exception {}; class InvalidStateRoot: public Exception {};
class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + asHex(m_head.ref()) + " block is:" + asHex(m_real.ref()); } }; class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } };
class InvalidTransaction: public Exception {}; class InvalidTransaction: public Exception {};
class InvalidDifficulty: public Exception {}; class InvalidDifficulty: public Exception {};
class InvalidTimestamp: public Exception {}; class InvalidTimestamp: public Exception {};

43
libethereum/ExtVMFace.h

@ -35,41 +35,52 @@ class ExtVMFace
public: public:
ExtVMFace() {} ExtVMFace() {}
ExtVMFace(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): ExtVMFace(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
fees(_fees),
previousBlock(_previousBlock), previousBlock(_previousBlock),
currentBlock(_currentBlock), currentBlock(_currentBlock),
currentNumber(_currentNumber) currentNumber(_currentNumber)
{} {}
ExtVMFace(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
myAddress(_myAddress), myAddress(_myAddress),
txSender(_txSender), caller(_caller),
txValue(_txValue), origin(_origin),
txData(_txData), value(_value),
fees(_fees), gasPrice(_gasPrice),
data(_data),
code(_code),
previousBlock(_previousBlock), previousBlock(_previousBlock),
currentBlock(_currentBlock), currentBlock(_currentBlock),
currentNumber(_currentNumber) currentNumber(_currentNumber)
{} {}
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; }
u256 store(u256 _n) { return 0; } u256 store(u256 _n) { return 0; }
void setStore(u256 _n, u256 _v) {} void setStore(u256 _n, u256 _v) {}
void mktx(Transaction& _t) {}
u256 balance(Address _a) { return 0; } u256 balance(Address _a) { return 0; }
void payFee(bigint _fee) {} void subBalance(u256 _a) {}
u256 txCount(Address _a) { return 0; } u256 txCount(Address _a) { return 0; }
u256 extro(Address _a, u256 _pos) { return 0; }
u256 extroPrice(Address _a) { return 0; }
void suicide(Address _a) {} void suicide(Address _a) {}
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) { return h160(); }
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _tx) { return false; }
#pragma GCC diagnostic pop
#pragma warning(pop)
Address myAddress; Address myAddress;
Address txSender; Address caller;
u256 txValue; Address origin;
u256s txData; u256 value;
FeeStructure fees; u256 gasPrice;
bytesConstRef data;
bytesConstRef code;
BlockInfo previousBlock; ///< The current block's information. BlockInfo previousBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information. BlockInfo currentBlock; ///< The current block's information.
uint currentNumber; uint currentNumber;
}; };

32
libethereum/FeeStructure.cpp

@ -24,26 +24,12 @@
using namespace std; using namespace std;
using namespace eth; using namespace eth;
u256 const c_stepFee = 1; u256 const eth::c_stepGas = 1;
u256 const c_dataFee = 20; u256 const eth::c_balanceGas = 20;
u256 const c_memoryFee = 5; u256 const eth::c_sha3Gas = 20;
u256 const c_extroFee = 40; u256 const eth::c_sloadGas = 20;
u256 const c_cryptoFee = 20; u256 const eth::c_sstoreGas = 100;
u256 const c_newContractFee = 100; u256 const eth::c_createGas = 100;
u256 const c_txFee = 100; u256 const eth::c_callGas = 20;
u256 const eth::c_memoryGas = 1;
void FeeStructure::setMultiplier(u256 _x) u256 const eth::c_txDataGas = 5;
{
m_stepFee = c_stepFee * _x;
m_dataFee = c_dataFee * _x;
m_memoryFee = c_memoryFee * _x;
m_extroFee = c_extroFee * _x;
m_cryptoFee = c_cryptoFee * _x;
m_newContractFee = c_newContractFee * _x;
m_txFee = c_txFee * _x;
}
u256 FeeStructure::multiplier() const
{
return m_stepFee / c_stepFee;
}

22
libethereum/FeeStructure.h

@ -26,18 +26,14 @@
namespace eth namespace eth
{ {
struct FeeStructure extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL.
{ extern u256 const c_balanceGas; ///< Once per BALANCE operation.
/// The fee structure. Values yet to be agreed on... extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
void setMultiplier(u256 _x); ///< The current block multiplier. extern u256 const c_sloadGas; ///< Once per SLOAD operation.
u256 multiplier() const; extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once).
u256 m_stepFee; extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
u256 m_dataFee; extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
u256 m_memoryFee; extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
u256 m_extroFee; extern u256 const c_txDataGas; ///< Per byte of data attached to a message-call transaction. NOTE: Not payable on data of calls between transactions.
u256 m_cryptoFee;
u256 m_newContractFee;
u256 m_txFee;
};
} }

25
libethereum/FixedHash.cpp

@ -0,0 +1,25 @@
/*
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 FixedHash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "FixedHash.h"
using namespace std;
using namespace eth;

195
libethereum/FixedHash.h

@ -0,0 +1,195 @@
/*
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 FixedHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <array>
#include <algorithm>
#include "CommonData.h"
namespace eth
{
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
/// Transparently converts to/from the corresponding arithmetic type; this will
/// assume the data contained in the hash is big-endian.
template <unsigned N>
class FixedHash
{
/// The corresponding arithmetic type.
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
public:
/// The size of the container.
enum { size = N };
/// A dummy flag to avoid accidental construction from pointer.
enum ConstructFromPointerType { ConstructFromPointer };
/// Method to convert from a string.
enum ConstructFromStringType { FromHex, FromBinary };
/// Construct an empty hash.
FixedHash() { m_data.fill(0); }
/// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<uint>(_b.size(), N)); }
/// Explicitly construct, copying from a bytes in memory with given pointer.
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
/// Explicitly construct, copying from a string.
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex): FixedHash(_t == FromHex ? fromHex(_s) : eth::asBytes(_s)) {}
/// Convert to arithmetic type.
operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash.
operator bool() const { return ((Arith)*this) != 0; }
// The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; }
// The obvious binary operators.
FixedHash& operator^=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; }
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
/// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
byte operator[](unsigned _i) const { return m_data[_i]; }
/// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + ".."; }
/// @returns a mutable byte vector_ref to the object's data.
bytesRef ref() { return bytesRef(m_data.data(), N); }
/// @returns a constant byte vector_ref to the object's data.
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data.
byte* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data.
byte const* data() const { return m_data.data(); }
/// @returns a copy of the object's data as a byte vector.
bytes asBytes() const { return bytes(data(), data() + N); }
/// @returns a mutable reference to the object's data as an STL array.
std::array<byte, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array.
std::array<byte, N> const& asArray() const { return m_data; }
/// A generic std::hash compatible function object.
struct hash
{
/// Make a hash of the object's data.
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << (5 - h)) + i;
return h;
}
};
private:
std::array<byte, N> m_data; ///< The binary data.
};
/// Fast equality operator for h256.
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
const uint64_t* hash1 = (const uint64_t*)this->data();
const uint64_t* hash2 = (const uint64_t*)_other.data();
return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
}
/// Fast std::hash compatible hash function object for h256.
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
}
/// Stream I/O for the FixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::setw(2) << (int)_h[i];
_out << std::dec;
return _out;
}
// Common types of FixedHash.
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t)
{
h160 ret;
memcpy(ret.data(), _t.data() + 12, 20);
return ret;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the left 20 bytes.
inline h160 left160(h256 const& _t)
{
h160 ret;
memcpy(&ret[0], _t.data(), 20);
return ret;
}
}
namespace std
{
/// Forward std::hash<eth::h256> to eth::h256::hash.
template<> struct hash<eth::h256>: eth::h256::hash {};
}

809
libethereum/Instruction.cpp

File diff suppressed because it is too large

123
libethereum/Instruction.h

@ -42,61 +42,108 @@ enum class Instruction: uint8_t
EXP, EXP,
NEG, NEG,
LT, LT,
LE,
GT, GT,
GE,
EQ, EQ,
NOT, NOT,
MYADDRESS, ///< pushes the transaction sender
TXSENDER, ///< pushes the transaction sender AND = 0x10,
TXVALUE , ///< pushes the transaction value OR,
TXDATAN, ///< pushes the number of data items XOR,
TXDATA, ///< pops one item and pushes data item S[-1], or zero if index out of range BYTE,
BLK_PREVHASH, ///< pushes the hash of the previous block (NOT the current one since that's impossible!)
BLK_COINBASE, ///< pushes the coinbase of the current block SHA3 = 0x20,
BLK_TIMESTAMP, ///< pushes the timestamp of the current block
BLK_NUMBER, ///< pushes the current block number ADDRESS = 0x30,
BLK_DIFFICULTY, ///< pushes the difficulty of the current block BALANCE,
BLK_NONCE, ORIGIN,
BASEFEE, CALLER,
SHA256 = 0x20, CALLVALUE,
RIPEMD160, CALLDATALOAD,
ECMUL, CALLDATASIZE,
ECADD, GASPRICE,
ECSIGN,
ECRECOVER, PREVHASH = 0x40,
ECVALID, COINBASE,
SHA3, TIMESTAMP,
PUSH = 0x30, NUMBER,
POP, DIFFICULTY,
GASLIMIT,
POP = 0x50,
DUP, DUP,
SWAP, SWAP,
MLOAD, MLOAD,
MSTORE, MSTORE,
MSTORE8,
SLOAD, SLOAD,
SSTORE, SSTORE,
JMP, JUMP,
JMPI, JUMPI,
IND, PC,
EXTRO, MEMSIZE,
BALANCE, GAS,
MKTX,
SUICIDE = 0x3f PUSH1 = 0x60,
PUSH2,
PUSH3,
PUSH4,
PUSH5,
PUSH6,
PUSH7,
PUSH8,
PUSH9,
PUSH10,
PUSH11,
PUSH12,
PUSH13,
PUSH14,
PUSH15,
PUSH16,
PUSH17,
PUSH18,
PUSH19,
PUSH20,
PUSH21,
PUSH22,
PUSH23,
PUSH24,
PUSH25,
PUSH26,
PUSH27,
PUSH28,
PUSH29,
PUSH30,
PUSH31,
PUSH32,
CREATE = 0xf0,
CALL,
RETURN,
SUICIDE = 0xff
}; };
/// Information structure for a particular instruction.
struct InstructionInfo struct InstructionInfo
{ {
char const* name; char const* name; ///< The name of the instruction.
int additional; int additional; ///< Additional items required in memory for this instructions (only for PUSH).
int args; int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
int ret; int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
}; };
/// Information on all the instructions.
extern const std::map<Instruction, InstructionInfo> c_instructionInfo; extern const std::map<Instruction, InstructionInfo> c_instructionInfo;
/// Convert from string mnemonic to Instruction type.
extern const std::map<std::string, Instruction> c_instructions; extern const std::map<std::string, Instruction> c_instructions;
u256s assemble(std::string const& _code, bool _quiet = false); /// Convert from simple EVM assembly language to EVM code.
std::string disassemble(u256s const& _mem); bytes assemble(std::string const& _code, bool _quiet = false);
u256s compileLisp(std::string const& _code, bool _quiet = false);
/// Convert from EVM code to simple EVM assembly language.
std::string disassemble(bytes const& _mem);
/// Compile a Low-level Lisp-like Language program into EVM-code.
bytes compileLisp(std::string const& _code, bool _quiet, bytes& _init);
} }

54
libethereum/Log.cpp

@ -0,0 +1,54 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Log.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Log.h"
#include <string>
#include <iostream>
using namespace std;
using namespace eth;
// Logging
int eth::g_logVerbosity = 8;
map<type_info const*, bool> eth::g_logOverride;
ThreadLocalLogName eth::t_logThreadName("main");
// foward declare without all of Windows.h
#ifdef _WIN32
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
#endif
void eth::simpleDebugOut(std::string const& _s, char const*)
{
cout << _s << endl << flush;
// helpful to use OutputDebugString on windows
#ifdef _WIN32
{
OutputDebugStringA(_s.data());
OutputDebugStringA("\n");
}
#endif
}
std::function<void(std::string const&, char const*)> eth::g_logPost = simpleDebugOut;

134
libethereum/Log.h

@ -0,0 +1,134 @@
/*
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 Log.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The logging subsystem.
*/
#pragma once
#include <ctime>
#include <chrono>
#include <boost/thread.hpp>
#include "vector_ref.h"
namespace eth
{
/// The null output stream. Used when logging is disabled.
class NullOutputStream
{
public:
template <class T> NullOutputStream& operator<<(T const&) { return *this; }
};
/// A simple log-output function that prints log messages to stdout.
void simpleDebugOut(std::string const&, char const* );
/// The logging system's current verbosity.
extern int g_logVerbosity;
/// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut().
extern std::function<void(std::string const&, char const*)> g_logPost;
/// Map of Log Channel types to bool, false forces the channel to be disabled, true forces it to be enabled.
/// If a channel has no entry, then it will output as long as its verbosity (LogChannel::verbosity) is less than
/// or equal to the currently output verbosity (g_logVerbosity).
extern std::map<std::type_info const*, bool> g_logOverride;
/// Associate a name with each thread for nice logging.
struct ThreadLocalLogName
{
ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); };
boost::thread_specific_ptr<std::string> m_name;
};
/// The current thread's name.
extern ThreadLocalLogName t_logThreadName;
/// Set the current thread's log name.
inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); }
/// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ).
/// Channels should inherit from LogChannel and define name() and verbosity.
struct LogChannel { static const char* name() { return " "; } static const int verbosity = 1; };
struct LeftChannel: public LogChannel { static const char* name() { return "<<<"; } };
struct RightChannel: public LogChannel { static const char* name() { return ">>>"; } };
struct WarnChannel: public LogChannel { static const char* name() { return "!!!"; } static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char* name() { return "***"; } };
struct DebugChannel: public LogChannel { static const char* name() { return "---"; } static const int verbosity = 0; };
/// Logging class, iostream-like, that can be shifted to.
template <class Id, bool _AutoSpacing = true>
class LogOutputStream
{
public:
/// Construct a new object.
/// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
LogOutputStream(bool _term = true)
{
std::type_info const* i = &typeid(Id);
auto it = g_logOverride.find(i);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && Id::verbosity <= g_logVerbosity))
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
m_sstr << Id::name() << " [ " << buf << " | " << *(t_logThreadName.m_name.get()) << (_term ? " ] " : "");
}
}
/// Destructor. Posts the accrued log entry to the g_logPost function.
~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); }
/// Shift arbitrary data to the log. Spaces will be added between items as required.
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; m_sstr << _t; } return *this; }
private:
std::stringstream m_sstr; ///< The accrued log entry.
};
// Simple cout-like stream objects for accessing common log channels.
// Dirties the global namespace, but oh so convenient...
#define cnote eth::LogOutputStream<eth::NoteChannel, true>()
#define cwarn eth::LogOutputStream<eth::WarnChannel, true>()
// Null stream-like objects.
#define ndebug if (true) {} else eth::NullOutputStream()
#define nlog(X) if (true) {} else eth::NullOutputStream()
#define nslog(X) if (true) {} else eth::NullOutputStream()
// Kill debugging log channel when we're in release mode.
#if NDEBUG
#define cdebug ndebug
#else
#define cdebug eth::LogOutputStream<eth::DebugChannel, true>()
#endif
// Kill all logs when when NLOG is defined.
#if NLOG
#define clog(X) nlog(X)
#define cslog(X) nslog(X)
#else
#define clog(X) eth::LogOutputStream<X, true>()
#define cslog(X) eth::LogOutputStream<X, false>()
#endif
}

1084
libethereum/PeerNetwork.cpp

File diff suppressed because it is too large

169
libethereum/PeerNetwork.h

@ -17,18 +17,18 @@
/** @file PeerNetwork.h /** @file PeerNetwork.h
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*
* Miscellanea required for the PeerServer/PeerSession classes.
*/ */
#pragma once #pragma once
#include <map> #include <string>
#include <memory>
#include <utility>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <thread> #include <chrono>
#include "RLP.h"
#include "Common.h" #include "Common.h"
#include "Log.h"
namespace ba = boost::asio; namespace ba = boost::asio;
namespace bi = boost::asio::ip; namespace bi = boost::asio::ip;
@ -37,8 +37,11 @@ namespace eth
bool isPrivateAddress(bi::address _addressToCheck); bool isPrivateAddress(bi::address _addressToCheck);
class Overlay;
class BlockChain; class BlockChain;
class TransactionQueue; class TransactionQueue;
class PeerServer;
class PeerSession;
struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; }; struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; };
struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; }; struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; };
@ -76,7 +79,8 @@ enum DisconnectReason
ClientQuit ClientQuit
}; };
class PeerServer; /// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
struct PeerInfo struct PeerInfo
{ {
@ -86,63 +90,7 @@ struct PeerInfo
std::chrono::steady_clock::duration lastPing; std::chrono::steady_clock::duration lastPing;
}; };
class PeerSession: public std::enable_shared_from_this<PeerSession> class UPnP;
{
friend class PeerServer;
public:
PeerSession(PeerServer* _server, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort = 0);
~PeerSession();
void start();
void disconnect(int _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
static int protocolVersion();
static int networkId();
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
private:
void dropped();
void doRead();
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
PeerServer* m_server;
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
uint m_networkId;
uint m_reqNetworkId;
unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
uint m_caps;
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
uint m_rating;
bool m_requireTransactions;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
};
enum class NodeMode enum class NodeMode
{ {
@ -150,99 +98,4 @@ enum class NodeMode
PeerServer PeerServer
}; };
class UPnP;
class PeerServer
{
friend class PeerSession;
public:
/// Start server, listening for connections on the given port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, unsigned short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m = NodeMode::Full);
~PeerServer();
/// Connect to a peer explicitly.
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
bool sync(BlockChain& _bc, TransactionQueue&, Overlay& _o);
bool sync();
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
void process() { if (isInitialised()) m_ioService.poll(); }
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
void setMode(NodeMode _m) { m_mode = _m; }
/// Get peer information.
std::vector<PeerInfo> peers() const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
bytes savePeers() const;
void restorePeers(bytesConstRef _b);
private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(BlockChain& _bc, TransactionQueue& _tq);
std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
unsigned short m_listenPort;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
uint m_requiredNetworkId;
std::map<Public, std::weak_ptr<PeerSession>> m_peers;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
std::chrono::steady_clock::time_point m_lastPeersRequest;
unsigned m_idealPeerCount = 5;
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
bool m_accepting = false;
};
} }

562
libethereum/PeerServer.cpp

@ -0,0 +1,562 @@
/*
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 PeerNetwork.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* Eric Lombrozo <elombrozo@gmail.com>
* @date 2014
*/
#include "PeerServer.h"
#include <sys/types.h>
#ifdef _WIN32
// winsock is already included
// #include <winsock.h>
#else
#include <ifaddrs.h>
#endif
#include <set>
#include <chrono>
#include <thread>
#include "Exceptions.h"
#include "Common.h"
#include "BlockChain.h"
#include "BlockInfo.h"
#include "TransactionQueue.h"
#include "UPnP.h"
#include "PeerSession.h"
using namespace std;
using namespace eth;
// Addresses we will skip during network interface discovery
// Use a vector as the list is small
// Why this and not names?
// Under MacOSX loopback (127.0.0.1) can be named lo0 and br0 are bridges (0.0.0.0)
static const set<bi::address> c_rejectAddresses = {
{bi::address_v4::from_string("127.0.0.1")},
{bi::address_v6::from_string("::1")},
{bi::address_v4::from_string("0.0.0.0")},
{bi::address_v6::from_string("::")}
};
PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, unsigned short _port, NodeMode _m, string const& _publicAddress, bool _upnp):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(_port),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, NodeMode _m, string const& _publicAddress, bool _upnp):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(0),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
m_listenPort = m_acceptor.local_endpoint().port();
// populate addresses.
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, NodeMode _m):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(0),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
// populate addresses.
populateAddresses();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::~PeerServer()
{
for (auto const& i: m_peers)
if (auto p = i.second.lock())
p->disconnect(ClientQuit);
delete m_upnp;
}
unsigned PeerServer::protocolVersion()
{
return 11;
}
void PeerServer::determinePublic(string const& _publicAddress, bool _upnp)
{
if (_upnp)
try
{
m_upnp = new UPnP;
}
catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly.
bi::tcp::resolver r(m_ioService);
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr: " << m_upnp->externalIP();
int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
{
// couldn't map
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming " << m_listenPort << " is local & external port.";
p = m_listenPort;
}
auto eip = m_upnp->externalIP();
if (eip == string("0.0.0.0") && _publicAddress.empty())
m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p);
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
m_addresses.push_back(m_public.address().to_v4());
}
}
else
{
// No UPnP - fallback on given public address or, if empty, the assumed peer address.
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
m_addresses.push_back(m_public.address().to_v4());
}
}
void PeerServer::populateAddresses()
{
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
throw NoNetworking();
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
WSACleanup();
throw NoNetworking();
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
clog(NetWarn) << "Bad host lookup.";
WSACleanup();
throw NoNetworking();
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
char *addrStr = inet_ntoa(addr);
bi::address ad(bi::address::from_string(addrStr));
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
throw NoNetworking();
bi::tcp::resolver r(m_ioService);
for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
char host[NI_MAXHOST];
if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
continue;
// TODO: Make exception safe when no internet.
auto it = r.resolve({host, "30303"});
bi::tcp::endpoint ep = it->endpoint();
bi::address ad = ep.address();
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
}
freeifaddrs(ifaddr);
#endif
}
std::map<Public, bi::tcp::endpoint> PeerServer::potentialPeers()
{
std::map<Public, bi::tcp::endpoint> ret;
if (!m_public.address().is_unspecified())
ret.insert(make_pair(m_key.pub(), m_public));
for (auto i: m_peers)
if (auto j = i.second.lock())
{
auto ep = j->endpoint();
// Skip peers with a listen port of zero or are on a private network
bool peerOnNet = (j->m_listenPort != 0 && !isPrivateAddress(ep.address()));
if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
}
return ret;
}
void PeerServer::ensureAccepting()
{
if (m_accepting == false)
{
clog(NetNote) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true;
m_acceptor.async_accept(m_socket, [=](boost::system::error_code ec)
{
if (!ec)
try
{
try {
clog(NetNote) << "Accepted connection from " << m_socket.remote_endpoint();
} catch (...){}
bi::address remoteAddress = m_socket.remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
auto p = std::make_shared<PeerSession>(this, std::move(m_socket), m_networkId, remoteAddress);
p->start();
}
catch (std::exception const& _e)
{
clog(NetWarn) << "ERROR: " << _e.what();
}
m_accepting = false;
if (ec.value() != 1 && (m_mode == NodeMode::PeerServer || m_peers.size() < m_idealPeerCount * 2))
ensureAccepting();
});
}
}
void PeerServer::connect(std::string const& _addr, unsigned short _port) noexcept
{
try
{
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port));
}
catch (exception const& e)
{
// Couldn't connect
clog(NetNote) << "Bad host " << _addr << " (" << e.what() << ")";
}
}
void PeerServer::connect(bi::tcp::endpoint const& _ep)
{
clog(NetNote) << "Attempting connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
{
clog(NetNote) << "Connection refused to " << _ep << " (" << ec.message() << ")";
for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i)
if (i->second.first == _ep && i->second.second < 3)
{
m_freePeers.push_back(i->first);
goto OK;
}
// for-else
clog(NetNote) << "Giving up.";
OK:;
}
else
{
auto p = make_shared<PeerSession>(this, std::move(*s), m_networkId, _ep.address(), _ep.port());
clog(NetNote) << "Connected to " << _ep;
p->start();
}
delete s;
});
}
bool PeerServer::sync()
{
bool ret = false;
if (isInitialised())
for (auto i = m_peers.begin(); i != m_peers.end();)
{
auto p = i->second.lock();
if (p && p->m_socket.is_open() &&
(p->m_disconnect == chrono::steady_clock::time_point::max() || chrono::steady_clock::now() - p->m_disconnect < chrono::seconds(1))) // kill old peers that should be disconnected.
++i;
else
{
i = m_peers.erase(i);
ret = true;
}
}
return ret;
}
bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq)
{
if (m_latestBlockSent == h256())
{
// First time - just initialise.
m_latestBlockSent = _bc.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent;
for (auto const& i: _tq.transactions())
m_transactionsSent.insert(i.first);
m_lastPeersRequest = chrono::steady_clock::time_point::min();
return true;
}
return false;
}
bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
{
bool ret = ensureInitialised(_bc, _tq);
if (sync())
ret = true;
if (m_mode == NodeMode::Full)
{
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
if (_tq.import(*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
auto h = _bc.currentHash();
bool resendAll = (h != m_latestBlockSent);
// Send any new transactions.
for (auto j: m_peers)
if (auto p = j.second.lock())
{
bytes b;
uint n = 0;
for (auto const& i: _tq.transactions())
if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions || resendAll)
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
if (n)
{
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
p->send(&b);
}
p->m_knownTransactions.clear();
p->m_requireTransactions = false;
}
// Send any new blocks.
if (h != m_latestBlockSent)
{
// TODO: find where they diverge and send complete new branch.
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(2) << BlocksPacket;
bytes b;
ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b);
seal(b);
for (auto j: m_peers)
if (auto p = j.second.lock())
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b);
p->m_knownBlocks.clear();
}
}
m_latestBlockSent = h;
for (int accepted = 1, n = 0; accepted; ++n)
{
accepted = 0;
if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it)
{
try
{
_bc.import(*it, _o);
it = m_incomingBlocks.erase(it);
++accepted;
ret = true;
}
catch (UnknownParent)
{
// Don't (yet) know its parent. Leave it for later.
m_unknownParentBlocks.push_back(*it);
it = m_incomingBlocks.erase(it);
}
catch (...)
{
// Some other error - erase it.
it = m_incomingBlocks.erase(it);
}
if (it == m_incomingBlocks.begin())
break;
}
if (!n && accepted)
{
for (auto i: m_unknownParentBlocks)
m_incomingBlocks.push_back(i);
m_unknownParentBlocks.clear();
}
}
// Connect to additional peers
while (m_peers.size() < m_idealPeerCount)
{
if (m_freePeers.empty())
{
if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
{
RLPStream s;
bytes b;
(PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
}
if (!m_accepting)
ensureAccepting();
break;
}
auto x = time(0) % m_freePeers.size();
m_incomingPeers[m_freePeers[x]].second++;
connect(m_incomingPeers[m_freePeers[x]].first);
m_freePeers.erase(m_freePeers.begin() + x);
}
}
// platform for consensus of social contract.
// restricts your freedom but does so fairly. and that's the value proposition.
// guarantees that everyone else respect the rules of the system. (i.e. obeys laws).
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
{
// look for worst peer to kick off
// first work out how many are old enough to kick off.
shared_ptr<PeerSession> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.second.lock())
if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
worst->disconnect(TooManyPeers);
}
return ret;
}
std::vector<PeerInfo> PeerServer::peers() const
{
const_cast<PeerServer*>(this)->pingAll();
this_thread::sleep_for(chrono::milliseconds(200));
std::vector<PeerInfo> ret;
for (auto& i: m_peers)
if (auto j = i.second.lock())
if (j->m_socket.is_open())
ret.push_back(j->m_info);
return ret;
}
void PeerServer::pingAll()
{
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
}
bytes PeerServer::savePeers() const
{
RLPStream ret;
int n = 0;
for (auto& i: m_peers)
if (auto p = i.second.lock())
if (p->m_socket.is_open() && p->endpoint().port())
{
ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
n++;
}
return RLPStream(n).appendRaw(ret.out(), n).out();
}
void PeerServer::restorePeers(bytesConstRef _b)
{
for (auto i: RLP(_b))
{
auto k = (Public)i[2];
if (!m_incomingPeers.count(k))
{
m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>()), 0)));
m_freePeers.push_back(k);
}
}
}

136
libethereum/PeerServer.h

@ -0,0 +1,136 @@
/*
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 PeerServer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <vector>
#include <set>
#include <memory>
#include <utility>
#include <thread>
#include "PeerNetwork.h"
#include "CommonEth.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
namespace eth
{
class PeerServer
{
friend class PeerSession;
public:
/// Start server, listening for connections on the given port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, unsigned short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, listening for connections on a system-assigned port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, unsigned int _networkId, NodeMode _m = NodeMode::Full);
~PeerServer();
static unsigned protocolVersion();
unsigned networkId() { return m_networkId; }
/// Connect to a peer explicitly.
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
bool sync(BlockChain& _bc, TransactionQueue&, Overlay& _o);
bool sync();
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
void process() { if (isInitialised()) m_ioService.poll(); }
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
void setMode(NodeMode _m) { m_mode = _m; }
/// Get peer information.
std::vector<PeerInfo> peers() const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
bytes savePeers() const;
void restorePeers(bytesConstRef _b);
private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(BlockChain& _bc, TransactionQueue& _tq);
std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
unsigned short m_listenPort;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
unsigned m_networkId;
std::map<Public, std::weak_ptr<PeerSession>> m_peers;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
std::chrono::steady_clock::time_point m_lastPeersRequest;
unsigned m_idealPeerCount = 5;
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
bool m_accepting = false;
};
}

587
libethereum/PeerSession.cpp

@ -0,0 +1,587 @@
/*
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 PeerSession.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "PeerSession.h"
#include <chrono>
#include "Exceptions.h"
#include "Common.h"
#include "BlockChain.h"
#include "BlockInfo.h"
#include "PeerServer.h"
using namespace std;
using namespace eth;
#define clogS(X) eth::LogOutputStream<X, true>(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.
static const eth::uint c_maxBlocksAsk = 256; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
PeerSession::PeerSession(PeerServer* _s, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort):
m_server(_s),
m_socket(std::move(_socket)),
m_reqNetworkId(_rNId),
m_listenPort(_peerPort),
m_rating(0)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0)});
}
PeerSession::~PeerSession()
{
m_socket.close();
}
bi::tcp::endpoint PeerSession::endpoint() const
{
if (m_socket.is_open())
try {
return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_listenPort);
} catch (...){}
return bi::tcp::endpoint();
}
// TODO: BUG! 256 -> work out why things start to break with big packet sizes -> g.t. ~370 blocks.
bool PeerSession::interpret(RLP const& _r)
{
clogS(NetRight) << _r;
switch (_r[0].toInt<unsigned>())
{
case HelloPacket:
{
m_protocolVersion = _r[1].toInt<uint>();
m_networkId = _r[2].toInt<uint>();
auto clientVersion = _r[3].toString();
m_caps = _r[4].toInt<uint>();
m_listenPort = _r[5].toInt<unsigned short>();
m_id = _r[6].toHash<h512>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort;
if (m_server->m_peers.count(m_id))
if (auto l = m_server->m_peers[m_id].lock())
if (l.get() != this && l->isOpen())
{
// Already connected.
cwarn << "Already have peer id" << m_id.abridged() << "at" << l->endpoint() << "rather than" << endpoint();
disconnect(DuplicatePeer);
return false;
}
if (m_protocolVersion != PeerServer::protocolVersion() || m_networkId != m_server->networkId() || !m_id)
{
disconnect(IncompatibleProtocol);
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration()}); }
catch (...)
{
disconnect(BadProtocol);
return false;
}
m_server->m_peers[m_id] = shared_from_this();
// Grab their block chain off them.
{
clogS(NetAllDetail) << "Want chain. Latest:" << m_server->m_latestBlockSent << ", number:" << m_server->m_chain->details(m_server->m_latestBlockSent).number;
uint count = std::min(c_maxHashes, m_server->m_chain->details(m_server->m_latestBlockSent).number + 1);
RLPStream s;
prep(s).appendList(2 + count);
s << GetChainPacket;
auto h = m_server->m_latestBlockSent;
for (uint i = 0; i < count; ++i, h = m_server->m_chain->details(h).parent)
{
clogS(NetAllDetail) << " " << i << ":" << h;
s << h;
}
s << c_maxBlocksAsk;
sealAndSend(s);
s.clear();
prep(s).appendList(1);
s << GetTransactionsPacket;
sealAndSend(s);
}
break;
}
case DisconnectPacket:
{
string reason = "Unspecified";
if (_r[1].isInt())
reason = reasonOf((DisconnectReason)_r[1].toInt<int>());
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
}
case PingPacket:
{
// clogS(NetMessageSummary) << "Ping";
RLPStream s;
sealAndSend(prep(s).appendList(1) << PongPacket);
break;
}
case PongPacket:
m_info.lastPing = std::chrono::steady_clock::now() - m_ping;
// clogS(NetMessageSummary) << "Latency: " << chrono::duration_cast<chrono::milliseconds>(m_lastPing).count() << " ms";
break;
case GetPeersPacket:
{
clogS(NetMessageSummary) << "GetPeers";
auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
for (auto i: peers)
{
clogS(NetMessageDetail) << "Sending peer " << toHex(i.first.ref().cropped(0, 4)) << i.second;
s.appendList(3) << i.second.address().to_v4().to_bytes() << i.second.port() << i.first;
}
sealAndSend(s);
break;
}
case PeersPacket:
clogS(NetMessageSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address_v4 peerAddress(_r[i][0].toArray<byte, 4>());
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>());
Public id = _r[i][2].toHash<Public>();
if (isPrivateAddress(peerAddress))
goto CONTINUE;
clogS(NetAllDetail) << "Checking: " << ep << "(" << toHex(id.ref().cropped(0, 4)) << ")";
// check that it's not us or one we already know:
if (id && (m_server->m_key.pub() == id || m_server->m_peers.count(id) || m_server->m_incomingPeers.count(id)))
goto CONTINUE;
// check that we're not already connected to addr:
if (!ep.port())
goto CONTINUE;
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
for (auto i: m_server->m_peers)
if (shared_ptr<PeerSession> p = i.second.lock())
{
clogS(NetAllDetail) << " ...against " << p->endpoint();
if (p->m_socket.is_open() && p->endpoint() == ep)
goto CONTINUE;
}
for (auto i: m_server->m_incomingPeers)
if (i.second.first == ep)
goto CONTINUE;
m_server->m_incomingPeers[id] = make_pair(ep, 0);
m_server->m_freePeers.push_back(id);
clogS(NetMessageDetail) << "New peer: " << ep << "(" << id << ")";
CONTINUE:;
}
break;
case TransactionsPacket:
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << " entries)";
m_rating += _r.itemCount() - 1;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
m_server->m_incomingTransactions.push_back(_r[i].data().toBytes());
m_knownTransactions.insert(sha3(_r[i].data()));
}
break;
case BlocksPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << " entries)";
unsigned used = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
if (!m_server->m_chain->details(h))
{
m_server->m_incomingBlocks.push_back(_r[i].data().toBytes());
m_knownBlocks.insert(h);
used++;
}
}
m_rating += used;
if (g_logVerbosity >= 3)
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
BlockInfo bi(_r[i].data());
if (!m_server->m_chain->details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
clogS(NetMessageDetail) << "Unknown parent " << bi.parentHash << " of block " << h;
else
clogS(NetMessageDetail) << "Known parent " << bi.parentHash << " of block " << h;
}
if (used) // we received some - check if there's any more
{
RLPStream s;
prep(s).appendList(3);
s << GetChainPacket;
s << sha3(_r[1].data());
s << c_maxBlocksAsk;
sealAndSend(s);
}
break;
}
case GetChainPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "GetChain (" << (_r.itemCount() - 2) << " hashes, " << (_r[_r.itemCount() - 1].toInt<bigint>()) << ")";
// ********************************************************************
// NEEDS FULL REWRITE!
h256s parents;
parents.reserve(_r.itemCount() - 2);
for (unsigned i = 1; i < _r.itemCount() - 1; ++i)
parents.push_back(_r[i].toHash<h256>());
if (_r.itemCount() == 2)
break;
// return 2048 block max.
uint baseCount = (uint)min<bigint>(_r[_r.itemCount() - 1].toInt<bigint>(), c_maxBlocks);
clogS(NetMessageSummary) << "GetChain (" << baseCount << " max, from " << parents.front() << " to " << parents.back() << ")";
for (auto parent: parents)
{
auto h = m_server->m_chain->currentHash();
h256 latest = m_server->m_chain->currentHash();
uint latestNumber = 0;
uint parentNumber = 0;
RLPStream s;
if (m_server->m_chain->details(parent))
{
latestNumber = m_server->m_chain->details(latest).number;
parentNumber = m_server->m_chain->details(parent).number;
uint count = min<uint>(latestNumber - parentNumber, baseCount);
clogS(NetAllDetail) << "Requires " << dec << (latestNumber - parentNumber) << " blocks from " << latestNumber << " to " << parentNumber;
clogS(NetAllDetail) << latest << " - " << parent;
prep(s);
s.appendList(1 + count) << BlocksPacket;
uint endNumber = m_server->m_chain->details(parent).number;
uint startNumber = endNumber + count;
clogS(NetAllDetail) << "Sending " << dec << count << " blocks from " << startNumber << " to " << endNumber;
uint n = latestNumber;
for (; n > startNumber; n--, h = m_server->m_chain->details(h).parent) {}
for (uint i = 0; i < count; ++i, --n, h = m_server->m_chain->details(h).parent)
{
if (h == parent || n == endNumber)
{
cwarn << "BUG! Couldn't create the reply for GetChain!";
return true;
}
clogS(NetAllDetail) << " " << dec << i << " " << h;
s.appendRaw(m_server->m_chain->block(h));
}
clogS(NetAllDetail) << "Parent: " << h;
}
else if (parent != parents.back())
continue;
if (h != parent)
{
// not in the blockchain;
if (parent == parents.back())
{
// out of parents...
clogS(NetAllDetail) << "GetChain failed; not in chain";
// No good - must have been on a different branch.
s.clear();
prep(s).appendList(2) << NotInChainPacket << parents.back();
}
else
// still some parents left - try them.
continue;
}
// send the packet (either Blocks or NotInChain) & exit.
sealAndSend(s);
break;
// ********************************************************************
}
break;
}
case NotInChainPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
h256 noGood = _r[1].toHash<h256>();
clogS(NetMessageSummary) << "NotInChain (" << noGood << ")";
if (noGood == m_server->m_chain->genesisHash())
{
clogS(NetWarn) << "Discordance over genesis block! Disconnect.";
disconnect(WrongGenesis);
}
else
{
uint count = std::min(c_maxHashes, m_server->m_chain->details(noGood).number);
RLPStream s;
prep(s).appendList(2 + count);
s << GetChainPacket;
auto h = m_server->m_chain->details(noGood).parent;
for (uint i = 0; i < count; ++i, h = m_server->m_chain->details(h).parent)
s << h;
s << c_maxBlocksAsk;
sealAndSend(s);
}
break;
}
case GetTransactionsPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
m_requireTransactions = true;
break;
}
default:
break;
}
return true;
}
void PeerSession::ping()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << PingPacket);
m_ping = std::chrono::steady_clock::now();
}
RLPStream& PeerSession::prep(RLPStream& _s)
{
return _s.appendRaw(bytes(8, 0));
}
void PeerServer::seal(bytes& _b)
{
_b[0] = 0x22;
_b[1] = 0x40;
_b[2] = 0x08;
_b[3] = 0x91;
uint32_t len = (uint32_t)_b.size() - 8;
_b[4] = (len >> 24) & 0xff;
_b[5] = (len >> 16) & 0xff;
_b[6] = (len >> 8) & 0xff;
_b[7] = len & 0xff;
}
void PeerSession::sealAndSend(RLPStream& _s)
{
bytes b;
_s.swapOut(b);
m_server->seal(b);
sendDestroy(b);
}
bool PeerSession::checkPacket(bytesConstRef _msg)
{
if (_msg.size() < 8)
return false;
if (!(_msg[0] == 0x22 && _msg[1] == 0x40 && _msg[2] == 0x08 && _msg[3] == 0x91))
return false;
uint32_t len = ((_msg[4] * 256 + _msg[5]) * 256 + _msg[6]) * 256 + _msg[7];
if (_msg.size() != len + 8)
return false;
RLP r(_msg.cropped(8));
if (r.actualSize() != len)
return false;
return true;
}
void PeerSession::sendDestroy(bytes& _msg)
{
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
if (!checkPacket(bytesConstRef(&_msg)))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
auto self(shared_from_this());
bytes* buffer = new bytes(std::move(_msg));
if (m_socket.is_open())
ba::async_write(m_socket, ba::buffer(*buffer), [self, buffer](boost::system::error_code ec, std::size_t /*length*/)
{
delete buffer;
if (ec)
{
cwarn << "Error sending: " << ec.message();
self->dropped();
}
// cbug << length << " bytes written (EC: " << ec << ")";
});
}
void PeerSession::send(bytesConstRef _msg)
{
clogS(NetLeft) << RLP(_msg.cropped(8));
if (!checkPacket(_msg))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
auto self(shared_from_this());
bytes* buffer = new bytes(_msg.toBytes());
if (m_socket.is_open())
ba::async_write(m_socket, ba::buffer(*buffer), [self, buffer](boost::system::error_code ec, std::size_t /*length*/)
{
delete buffer;
if (ec)
{
cwarn << "Error sending: " << ec.message();
self->dropped();
}
// cbug << length << " bytes written (EC: " << ec << ")";
});
}
void PeerSession::dropped()
{
if (m_socket.is_open())
try {
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
m_socket.close();
}catch (...){}
for (auto i = m_server->m_peers.begin(); i != m_server->m_peers.end(); ++i)
if (i->second.lock().get() == this)
{
m_server->m_peers.erase(i);
break;
}
}
void PeerSession::disconnect(int _reason)
{
clogS(NetNote) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s);
s.appendList(2) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
else
dropped();
}
}
void PeerSession::start()
{
RLPStream s;
prep(s);
s.appendList(7) << HelloPacket << (uint)PeerServer::protocolVersion() << m_server->networkId() << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
doRead();
}
void PeerSession::doRead()
{
auto self(shared_from_this());
m_socket.async_read_some(boost::asio::buffer(m_data), [this,self](boost::system::error_code ec, std::size_t length)
{
if (ec)
{
cwarn << "Error reading: " << ec.message();
dropped();
}
else
{
try
{
m_incoming.resize(m_incoming.size() + length);
memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length);
while (m_incoming.size() > 8)
{
if (m_incoming[0] != 0x22 || m_incoming[1] != 0x40 || m_incoming[2] != 0x08 || m_incoming[3] != 0x91)
{
clogS(NetWarn) << "Out of alignment.";
disconnect(BadProtocol);
return;
clogS(NetNote) << "Skipping: " << hex << showbase << (int)m_incoming[0] << dec;
memmove(m_incoming.data(), m_incoming.data() + 1, m_incoming.size() - 1);
m_incoming.resize(m_incoming.size() - 1);
}
else
{
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4));
uint32_t tlen = len + 8;
if (m_incoming.size() < tlen)
break;
// enough has come in.
// cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
auto data = bytesConstRef(m_incoming.data(), tlen);
if (!checkPacket(data))
{
cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
cwarn << "INVALID MESSAGE RECEIVED";
disconnect(BadProtocol);
return;
}
else
{
RLP r(data.cropped(8));
if (!interpret(r))
{
// error
dropped();
return;
}
}
memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen);
m_incoming.resize(m_incoming.size() - tlen);
}
}
doRead();
}
catch (Exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.description();
dropped();
}
catch (std::exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.what();
dropped();
}
}
});
}

90
libethereum/PeerSession.h

@ -0,0 +1,90 @@
/*
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 PeerSession.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <array>
#include <set>
#include <memory>
#include <utility>
#include "RLP.h"
#include "CommonEth.h"
#include "PeerNetwork.h"
namespace eth
{
class PeerSession: public std::enable_shared_from_this<PeerSession>
{
friend class PeerServer;
public:
PeerSession(PeerServer* _server, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort = 0);
~PeerSession();
void start();
void disconnect(int _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
private:
void dropped();
void doRead();
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
PeerServer* m_server;
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
uint m_networkId;
uint m_reqNetworkId;
unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
uint m_caps;
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
uint m_rating;
bool m_requireTransactions;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
};
}

11
libethereum/RLP.h

@ -283,8 +283,9 @@ public:
RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list. /// Appends a sequence of data to the stream as a list.
template <class _T> RLPStream& append(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } template <class _T> RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); }
template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
/// Appends a list. /// Appends a list.
RLPStream& appendList(uint _items); RLPStream& appendList(uint _items);
@ -324,14 +325,6 @@ private:
*(b--) = (byte)_i; *(b--) = (byte)_i;
} }
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T> static uint bytesRequired(_T _i)
{
uint i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
/// Our output byte stream. /// Our output byte stream.
bytes m_out; bytes m_out;

316
libethereum/State.cpp

@ -42,10 +42,10 @@ std::map<Address, AddressState> const& eth::genesisState()
if (s_ret.empty()) if (s_ret.empty())
{ {
// Initialise. // Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
} }
return s_ret; return s_ret;
} }
@ -56,6 +56,9 @@ Overlay State::openDB(std::string _path, bool _killExisting)
_path = Defaults::get()->m_dbPath; _path = Defaults::get()->m_dbPath;
boost::filesystem::create_directory(_path); boost::filesystem::create_directory(_path);
if (_killExisting)
boost::filesystem::remove_all(_path + "/state");
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
ldb::DB* db = nullptr; ldb::DB* db = nullptr;
@ -69,7 +72,6 @@ State::State(Address _coinbaseAddress, Overlay const& _db):
m_ourAddress(_coinbaseAddress) m_ourAddress(_coinbaseAddress)
{ {
m_blockReward = 1500 * finney; m_blockReward = 1500 * finney;
m_fees.setMultiplier(100 * szabo);
secp256k1_start(); secp256k1_start();
@ -95,7 +97,6 @@ State::State(State const& _s):
m_currentBlock(_s.m_currentBlock), m_currentBlock(_s.m_currentBlock),
m_currentNumber(_s.m_currentNumber), m_currentNumber(_s.m_currentNumber),
m_ourAddress(_s.m_ourAddress), m_ourAddress(_s.m_ourAddress),
m_fees(_s.m_fees),
m_blockReward(_s.m_blockReward) m_blockReward(_s.m_blockReward)
{ {
} }
@ -111,15 +112,19 @@ State& State::operator=(State const& _s)
m_currentBlock = _s.m_currentBlock; m_currentBlock = _s.m_currentBlock;
m_currentNumber = _s.m_currentNumber; m_currentNumber = _s.m_currentNumber;
m_ourAddress = _s.m_ourAddress; m_ourAddress = _s.m_ourAddress;
m_fees = _s.m_fees;
m_blockReward = _s.m_blockReward; m_blockReward = _s.m_blockReward;
return *this; return *this;
} }
void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{ {
auto it = m_cache.find(_a); ensureCached(m_cache, _a, _requireMemory, _forceCreate);
if (it == m_cache.end()) }
void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bool _requireMemory, bool _forceCreate) const
{
auto it = _cache.find(_a);
if (it == _cache.end())
{ {
// populate basic info. // populate basic info.
string stateBack = m_state.at(_a); string stateBack = m_state.at(_a);
@ -132,25 +137,18 @@ void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) con
else if (state.itemCount() == 2) else if (state.itemCount() == 2)
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>()); s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>());
else else
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>()); s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].toHash<h256>());
bool ok; bool ok;
tie(it, ok) = m_cache.insert(make_pair(_a, s)); tie(it, ok) = _cache.insert(make_pair(_a, s));
} }
if (_requireMemory && !it->second.haveMemory()) if (_requireMemory && !it->second.isComplete())
{ {
// Populate memory. // Populate memory.
assert(it->second.type() == AddressType::Contract); assert(it->second.type() == AddressType::Contract);
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :) TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
map<u256, u256>& mem = it->second.setHaveMemory(); map<u256, u256>& mem = it->second.setIsComplete(bytesConstRef(m_db.lookup(it->second.codeHash())));
for (auto const& i: memdb) for (auto const& i: memdb)
#ifdef __clang__
if (mem.find(i.first) == mem.end())
mem.insert(make_pair(i.first, RLP(i.second).toInt<u256>()));
else
mem.at(i.first) = RLP(i.second).toInt<u256>();
#else
mem[i.first] = RLP(i.second).toInt<u256>(); mem[i.first] = RLP(i.second).toInt<u256>();
#endif
} }
} }
@ -365,6 +363,7 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _
u256 tdIncrease = m_currentBlock.difficulty; u256 tdIncrease = m_currentBlock.difficulty;
// Check uncles & apply their rewards to state. // Check uncles & apply their rewards to state.
// TODO: Check for uniqueness of uncles.
Addresses rewarded; Addresses rewarded;
for (auto const& i: RLP(_block)[2]) for (auto const& i: RLP(_block)[2])
{ {
@ -567,13 +566,13 @@ u256 State::transactionsFrom(Address _id) const
return it->second.nonce(); return it->second.nonce();
} }
u256 State::contractMemory(Address _id, u256 _memory) const u256 State::contractStorage(Address _id, u256 _memory) const
{ {
ensureCached(_id, false, false); ensureCached(_id, false, false);
auto it = m_cache.find(_id); auto it = m_cache.find(_id);
if (it == m_cache.end() || it->second.type() != AddressType::Contract) if (it == m_cache.end() || it->second.type() != AddressType::Contract)
return 0; return 0;
else if (it->second.haveMemory()) else if (it->second.isComplete())
{ {
auto mit = it->second.memory().find(_memory); auto mit = it->second.memory().find(_memory);
if (mit == it->second.memory().end()) if (mit == it->second.memory().end())
@ -586,7 +585,7 @@ u256 State::contractMemory(Address _id, u256 _memory) const
return ret.size() ? RLP(ret).toInt<u256>() : 0; return ret.size() ? RLP(ret).toInt<u256>() : 0;
} }
map<u256, u256> const& State::contractMemory(Address _contract) const map<u256, u256> const& State::contractStorage(Address _contract) const
{ {
if (!isContractAddress(_contract)) if (!isContractAddress(_contract))
return EmptyMapU256U256; return EmptyMapU256U256;
@ -594,144 +593,209 @@ map<u256, u256> const& State::contractMemory(Address _contract) const
return m_cache[_contract].memory(); return m_cache[_contract].memory();
} }
bytes const& State::contractCode(Address _contract) const
{
if (!isContractAddress(_contract))
return EmptyBytes;
ensureCached(_contract, true, true);
return m_cache[_contract].code();
}
void State::execute(bytesConstRef _rlp) void State::execute(bytesConstRef _rlp)
{ {
// Entry point for a user-executed transaction. // Entry point for a user-executed transaction.
Transaction t(_rlp); Transaction t(_rlp);
executeBare(t, t.sender());
// Add to the user-originated transactions that we've executed. auto sender = t.sender();
// NOTE: Here, contract-originated transactions will not get added to the transaction list.
// If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and
// don't forget to allow unsigned transactions in the tx list if they concur with the script execution.
m_transactions.push_back(t);
m_transactionSet.insert(t.sha3());
}
void State::applyRewards(Addresses const& _uncleAddresses) // Avoid invalid transactions.
{ auto nonceReq = transactionsFrom(sender);
u256 r = m_blockReward; if (t.nonce != nonceReq)
for (auto const& i: _uncleAddresses)
{ {
addBalance(i, m_blockReward * 3 / 4); clog(StateChat) << "Invalid Nonce.";
r += m_blockReward / 8; throw InvalidNonce(nonceReq, t.nonce);
} }
addBalance(m_currentBlock.coinbaseAddress, r);
}
void State::unapplyRewards(Addresses const& _uncleAddresses) // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas proce discovery protocol going.
{ if (t.gasPrice < 10 * szabo)
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
{ {
subBalance(i, m_blockReward * 3 / 4); clog(StateChat) << "Offered gas-price is too low.";
r += m_blockReward / 8; throw GasPriceTooLow();
} }
subBalance(m_currentBlock.coinbaseAddress, r);
}
void State::executeBare(Transaction const& _t, Address _sender) // Check gas cost is enough.
{ u256 gasCost;
#if ETH_DEBUG if (t.isCreation())
commit(); gasCost = (t.init.size() + t.data.size()) * c_txDataGas + c_createGas;
clog(StateChat) << "State:" << rootHash(); else
clog(StateChat) << "Executing TX:" << _t; gasCost = t.data.size() * c_txDataGas + c_callGas;
#endif
// Entry point for a contract-originated transaction.
// Ignore invalid transactions. if (t.gas < gasCost)
auto nonceReq = transactionsFrom(_sender);
if (_t.nonce != nonceReq)
{ {
clog(StateChat) << "Invalid Nonce."; clog(StateChat) << "Not enough gas to pay for the transaction.";
throw InvalidNonce(nonceReq, _t.nonce); throw OutOfGas();
} }
unsigned nonZeroData = 0; u256 cost = t.value + t.gas * t.gasPrice;
for (auto i: _t.data)
if (i)
nonZeroData++;
u256 fee = _t.receiveAddress ? m_fees.m_txFee : (nonZeroData * m_fees.m_memoryFee + m_fees.m_newContractFee);
// Not considered invalid - just pointless. // Avoid unaffordable transactions.
if (balance(_sender) < _t.value + fee) if (balance(sender) < cost)
{ {
clog(StateChat) << "Not enough cash."; clog(StateChat) << "Not enough cash.";
throw NotEnoughCash(); throw NotEnoughCash();
} }
if (_t.receiveAddress) u256 gas = t.gas - gasCost;
{
// Increment associated nonce for sender.
noteSending(_sender);
// Pay... // Increment associated nonce for sender.
subBalance(_sender, _t.value + fee); noteSending(sender);
addBalance(_t.receiveAddress, _t.value);
if (isContractAddress(_t.receiveAddress)) // Pay...
{ cnote << "Paying" << formatBalance(cost) << "from sender (includes" << t.gas << "gas at" << formatBalance(t.gasPrice) << ")";
// Once we get here, there's no going back. subBalance(sender, cost);
try
{ if (t.isCreation())
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction. create(sender, t.value, t.gasPrice, &gas, &t.data, &t.init);
execute(_t.receiveAddress, _sender, _t.value, _t.data, &feeAdder.fee);
}
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << _e.description();
}
catch (std::exception const& _e)
{
clog(StateChat) << "std::exception in VM: " << _e.what();
}
}
}
else else
call(t.receiveAddress, sender, t.value, t.gasPrice, bytesConstRef(&t.data), &gas, bytesRef());
cnote << "Refunding" << formatBalance(gas * t.gasPrice) << "to sender (=" << gas << "*" << formatBalance(t.gasPrice) << ")";
addBalance(sender, gas * t.gasPrice);
u256 gasSpent = (t.gas - gas) * t.gasPrice;
/* unsigned c_feesKept = 8;
u256 feesEarned = gasSpent - (gasSpent / c_feesKept);
cnote << "Transferring" << (100.0 - 100.0 / c_feesKept) << "% of" << formatBalance(gasSpent) << "=" << formatBalance(feesEarned) << "to miner (" << formatBalance(gasSpent - feesEarned) << "is burnt).";
*/
u256 feesEarned = gasSpent;
cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
addBalance(m_currentBlock.coinbaseAddress, feesEarned);
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(t);
m_transactionSet.insert(t.sha3());
}
bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress)
{
if (!_originAddress)
_originAddress = _senderAddress;
cnote << "Transferring" << formatBalance(_value) << "to receiver.";
addBalance(_receiveAddress, _value);
if (isContractAddress(_receiveAddress))
{ {
Address newAddress = right160(_t.sha3()); VM vm(*_gas);
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &contractCode(_receiveAddress));
bool revert = false;
if (isContractAddress(newAddress) || isNormalAddress(newAddress)) try
{
auto out = vm.go(evm);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
}
catch (OutOfGas const& /*_e*/)
{
clog(StateChat) << "Out of Gas! Reverting.";
revert = true;
}
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << _e.description();
}
catch (std::exception const& _e)
{ {
clog(StateChat) << "Contract address collision."; clog(StateChat) << "std::exception in VM: " << _e.what();
throw ContractAddressCollision();
} }
// Increment associated nonce for sender. // Write state out only in the case of a non-excepted transaction.
noteSending(_sender); if (revert)
evm.revert();
// Pay out of sender... *_gas = vm.gas();
subBalance(_sender, _t.value + fee);
// Set up new account... return !revert;
m_cache[newAddress] = AddressState(_t.value, 0, AddressType::Contract);
auto& mem = m_cache[newAddress].memory();
for (uint i = 0; i < _t.data.size(); ++i)
#ifdef __clang__
if (mem.find(i) == mem.end())
mem.insert(make_pair(i, _t.data[i]));
else
mem.at(i) = _t.data[i];
#else
mem[i] = _t.data[i];
#endif
} }
return true;
}
#if ETH_DEBUG h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init, Address _origin)
commit(); {
clog(StateChat) << "New state:" << rootHash(); if (!_origin)
#endif _origin = _sender;
Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
while (isContractAddress(newAddress) || isNormalAddress(newAddress))
newAddress = (u160)newAddress + 1;
// Set up new account...
m_cache[newAddress] = AddressState(0, 0, _code);
// Execute _init.
VM vm(*_gas);
ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init);
bool revert = false;
try
{
/*auto out =*/ vm.go(evm);
// Don't do anything with the output (yet).
//memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
}
catch (OutOfGas const& /*_e*/)
{
clog(StateChat) << "Out of Gas! Reverting.";
revert = true;
}
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << _e.description();
}
catch (std::exception const& _e)
{
clog(StateChat) << "std::exception in VM: " << _e.what();
}
// Write state out only in the case of a non-excepted transaction.
if (revert)
{
evm.revert();
m_cache.erase(newAddress);
newAddress = Address();
}
*_gas = vm.gas();
return newAddress;
}
void State::applyRewards(Addresses const& _uncleAddresses)
{
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
{
addBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
}
addBalance(m_currentBlock.coinbaseAddress, r);
} }
void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* _totalFee) void State::unapplyRewards(Addresses const& _uncleAddresses)
{ {
VM vm; u256 r = m_blockReward;
ExtVM evm(*this, _myAddress, _txSender, _txValue, _txData); for (auto const& i: _uncleAddresses)
vm.go(evm); {
*_totalFee = vm.runFee(); subBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
}
subBalance(m_currentBlock.coinbaseAddress, r);
} }

117
libethereum/State.h

@ -46,6 +46,8 @@ std::map<Address, AddressState> const& genesisState();
static const std::map<u256, u256> EmptyMapU256U256; static const std::map<u256, u256> EmptyMapU256U256;
static const bytes EmptyBytes;
struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; }; struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; };
class ExtVM; class ExtVM;
@ -76,7 +78,7 @@ public:
Address address() const { return m_ourAddress; } Address address() const { return m_ourAddress; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
static Overlay openDB(std::string _path, bool _killExisting = false); static Overlay openDB(std::string _path, bool _killExisting = false);
static Overlay openDB(bool _killExisting = false) { return openDB(std::string(), _killExisting); } static Overlay openDB(bool _killExisting = false) { return openDB(std::string(), _killExisting); }
/// @returns the set containing all addresses currently in use in Ethereum. /// @returns the set containing all addresses currently in use in Ethereum.
@ -119,6 +121,7 @@ public:
bool cull(TransactionQueue& _tq) const; bool cull(TransactionQueue& _tq) const;
/// Execute a given transaction. /// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
void execute(bytes const& _rlp) { return execute(&_rlp); } void execute(bytes const& _rlp) { return execute(&_rlp); }
void execute(bytesConstRef _rlp); void execute(bytesConstRef _rlp);
@ -144,11 +147,15 @@ public:
/// Get the value of a memory position of a contract. /// Get the value of a memory position of a contract.
/// @returns 0 if no contract exists at that address. /// @returns 0 if no contract exists at that address.
u256 contractMemory(Address _contract, u256 _memory) const; u256 contractStorage(Address _contract, u256 _memory) const;
/// Get the memory of a contract. /// Get the memory of a contract.
/// @returns std::map<u256, u256> if no contract exists at that address. /// @returns std::map<u256, u256> if no contract exists at that address.
std::map<u256, u256> const& contractMemory(Address _contract) const; std::map<u256, u256> const& contractStorage(Address _contract) const;
/// Get the code of a contract.
/// @returns bytes() if no contract exists at that address.
bytes const& contractCode(Address _contract) const;
/// Note that the given address is sending a transaction and thus increment the associated ticker. /// Note that the given address is sending a transaction and thus increment the associated ticker.
void noteSending(Address _id); void noteSending(Address _id);
@ -170,26 +177,21 @@ public:
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit); u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit);
/// Get the fee associated for a contract created with the given data. /// Get the fee associated for a contract created with the given data.
u256 fee(uint _dataCount) const { return m_fees.m_memoryFee * _dataCount + m_fees.m_newContractFee; } u256 createGas(uint _dataCount, u256 _gas = 0) const { return c_txDataGas * _dataCount + c_createGas + _gas; }
/// Get the fee associated for a normal transaction. /// Get the fee associated for a normal transaction.
u256 fee() const { return m_fees.m_txFee; } u256 callGas(uint _dataCount, u256 _gas = 0) const { return c_txDataGas * _dataCount + c_callGas + _gas; }
private: private:
/// Fee-adder on destruction RAII class.
struct MinerFeeAdder
{
~MinerFeeAdder() { /*state->addBalance(state->m_currentBlock.coinbaseAddress, fee);*/ } // No fees paid now.
State* state;
u256 fee;
};
/// Retrieve all information about a given address into the cache. /// Retrieve all information about a given address into the cache.
/// If _requireMemory is true, grab the full memory should it be a contract item. /// If _requireMemory is true, grab the full memory should it be a contract item.
/// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't /// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't
/// exist in the DB. /// exist in the DB.
void ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const; void ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const;
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map<Address, AddressState>& _cache, Address _a, bool _requireMemory, bool _forceCreate) const;
/// Commit all changes waiting in the address cache to the DB. /// Commit all changes waiting in the address cache to the DB.
void commit(); void commit();
@ -201,12 +203,16 @@ private:
/// Throws on failure. /// Throws on failure.
u256 playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit); u256 playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit);
/// Execute a decoded transaction object, given a sender. // Two priviledged entry points for transaction processing used by the VM (these don't get added to the Transaction lists):
/// This will append @a _t to the transaction list and change the state accordingly. // We assume all instrinsic fees are paid up before this point.
void executeBare(Transaction const& _t, Address _sender);
/// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init, Address _originAddress = Address());
/// Execute a contract transaction. /// Execute a call.
void execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* o_totalFee); /// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise.
bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address());
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent(); void resetCurrent();
@ -236,7 +242,6 @@ private:
Dagger m_dagger; Dagger m_dagger;
FeeStructure m_fees;
u256 m_blockReward; u256 m_blockReward;
static std::string c_defaultPath; static std::string c_defaultPath;
@ -247,8 +252,8 @@ private:
class ExtVM: public ExtVMFace class ExtVM: public ExtVMFace
{ {
public: public:
ExtVM(State& _s, Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData): ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code):
ExtVMFace(_myAddress, _txSender, _txValue, _txData, _s.m_fees, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s) ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s), m_origCache(_s.m_cache)
{ {
m_s.ensureCached(_myAddress, true, true); m_s.ensureCached(_myAddress, true, true);
m_store = &(m_s.m_cache[_myAddress].memory()); m_store = &(m_s.m_cache[_myAddress].memory());
@ -262,45 +267,41 @@ public:
void setStore(u256 _n, u256 _v) void setStore(u256 _n, u256 _v)
{ {
if (_v) if (_v)
{
#ifdef __clang__
auto it = m_store->find(_n);
if (it == m_store->end())
m_store->insert(std::make_pair(_n, _v));
else
m_store->at(_n) = _v;
#else
(*m_store)[_n] = _v; (*m_store)[_n] = _v;
#endif
}
else else
m_store->erase(_n); m_store->erase(_n);
} }
void payFee(bigint _f) h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{ {
if (_f > m_s.balance(myAddress)) // Increment associated nonce for sender.
throw NotEnoughCash(); m_s.noteSending(myAddress);
m_s.subBalance(myAddress, _f);
return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, _init, origin);
} }
void mktx(Transaction& _t) bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)
{ {
_t.nonce = m_s.transactionsFrom(myAddress); return m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin);
m_s.executeBare(_t, myAddress);
} }
u256 balance(Address _a) { return m_s.balance(_a); } u256 balance(Address _a) { return m_s.balance(_a); }
void subBalance(u256 _a) { m_s.subBalance(myAddress, _a); }
u256 txCount(Address _a) { return m_s.transactionsFrom(_a); } u256 txCount(Address _a) { return m_s.transactionsFrom(_a); }
u256 extro(Address _a, u256 _pos) { return m_s.contractMemory(_a, _pos); }
u256 extroPrice(Address _a) { return 0; }
void suicide(Address _a) void suicide(Address _a)
{ {
m_s.addBalance(_a, m_s.balance(myAddress) + m_store->size() * fees.m_memoryFee); m_s.addBalance(_a, m_s.balance(myAddress));
m_s.m_cache[myAddress].kill(); m_s.m_cache[myAddress].kill();
} }
void revert()
{
m_s.m_cache = m_origCache;
}
private: private:
State& m_s; State& m_s;
std::map<Address, AddressState> m_origCache;
std::map<u256, u256>* m_store; std::map<u256, u256>* m_store;
}; };
@ -322,16 +323,8 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
std::map<u256, u256> mem; std::map<u256, u256> mem;
for (auto const& j: memdb) for (auto const& j: memdb)
{ {
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]"; _out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
#ifdef __clang__
auto mFinder = mem.find(j.first);
if (mFinder == mem.end())
mem.insert(std::make_pair(j.first, RLP(j.second).toInt<u256>()));
else
mFinder->second = RLP(j.second).toInt<u256>();
#else
mem[j.first] = RLP(j.second).toInt<u256>(); mem[j.first] = RLP(j.second).toInt<u256>();
#endif
} }
_out << std::endl << mem; _out << std::endl << mem;
} }
@ -348,7 +341,7 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
_out << (d.count(i.first) ? "[ ! " : "[ * ") << (i.second.type() == AddressType::Contract ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << i.second.nonce() << "@" << i.second.balance(); _out << (d.count(i.first) ? "[ ! " : "[ * ") << (i.second.type() == AddressType::Contract ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << i.second.nonce() << "@" << i.second.balance();
if (i.second.type() == AddressType::Contract) if (i.second.type() == AddressType::Contract)
{ {
if (i.second.haveMemory()) if (i.second.isComplete())
{ {
_out << std::endl << i.second.memory(); _out << std::endl << i.second.memory();
} }
@ -359,16 +352,8 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
std::map<u256, u256> mem; std::map<u256, u256> mem;
for (auto const& j: memdb) for (auto const& j: memdb)
{ {
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]"; _out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
#ifdef __clang__
auto mFinder = mem.find(j.first);
if (mFinder == mem.end())
mem.insert(std::make_pair(j.first, RLP(j.second).toInt<u256>()));
else
mFinder->second = RLP(j.second).toInt<u256>();
#else
mem[j.first] = RLP(j.second).toInt<u256>(); mem[j.first] = RLP(j.second).toInt<u256>();
#endif
} }
_out << std::endl << mem; _out << std::endl << mem;
} }
@ -390,7 +375,7 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
s << i.second.balance() << i.second.nonce(); s << i.second.balance() << i.second.nonce();
if (i.second.type() == AddressType::Contract) if (i.second.type() == AddressType::Contract)
{ {
if (i.second.haveMemory()) if (i.second.isComplete())
{ {
TrieDB<h256, DB> memdb(&_db); TrieDB<h256, DB> memdb(&_db);
memdb.init(); memdb.init();
@ -398,9 +383,17 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
if (j.second) if (j.second)
memdb.insert(j.first, rlp(j.second)); memdb.insert(j.first, rlp(j.second));
s << memdb.root(); s << memdb.root();
if (i.second.freshCode())
{
h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code());
s << ch;
}
else
s << i.second.codeHash();
} }
else else
s << i.second.oldRoot(); s << i.second.oldRoot() << i.second.codeHash();
} }
_state.insert(i.first, &s.out()); _state.insert(i.first, &s.out());
} }

27
libethereum/Transaction.cpp

@ -23,6 +23,7 @@
#include "vector_ref.h" #include "vector_ref.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "Transaction.h" #include "Transaction.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -35,12 +36,18 @@ Transaction::Transaction(bytesConstRef _rlpData)
try try
{ {
nonce = rlp[field = 0].toInt<u256>(); nonce = rlp[field = 0].toInt<u256>();
receiveAddress = rlp[field = 1].toHash<Address>(); value = rlp[field = 1].toInt<u256>();
value = rlp[field = 2].toInt<u256>(); receiveAddress = rlp[field = 2].toHash<Address>();
data.reserve(rlp[field = 3].itemCountStrict()); gasPrice = rlp[field = 3].toInt<u256>();
for (auto const& i: rlp[3]) gas = rlp[field = 4].toInt<u256>();
data.push_back(i.toInt<u256>()); data = rlp[field = 5].toBytes();
vrs = Signature{ rlp[field = 4].toInt<byte>(), rlp[field = 5].toInt<u256>(), rlp[field = 6].toInt<u256>() }; if (isCreation())
{
init = rlp[field = 6].toBytes();
vrs = Signature{ rlp[field = 7].toInt<byte>(), rlp[field = 8].toInt<u256>(), rlp[field = 9].toInt<u256>() };
}
else
vrs = Signature{ rlp[field = 6].toInt<byte>(), rlp[field = 7].toInt<u256>(), rlp[field = 8].toInt<u256>() };
} }
catch (RLPException const&) catch (RLPException const&)
{ {
@ -79,7 +86,7 @@ Address Transaction::sender() const
cout << "---- RECOVER -------------------------------" << endl; cout << "---- RECOVER -------------------------------" << endl;
cout << "MSG: " << msg << endl; cout << "MSG: " << msg << endl;
cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl; cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl;
cout << "PUB: " << asHex(bytesConstRef(&(pubkey[1]), 64)) << endl; cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl; cout << "ADR: " << ret << endl;
#endif #endif
return ret; return ret;
@ -112,8 +119,10 @@ void Transaction::sign(Secret _priv)
void Transaction::fillStream(RLPStream& _s, bool _sig) const void Transaction::fillStream(RLPStream& _s, bool _sig) const
{ {
_s.appendList(_sig ? 7 : 4); _s.appendList((_sig ? 3 : 0) + (isCreation() ? 7 : 6));
_s << nonce << receiveAddress << value << data; _s << nonce << value << receiveAddress << gasPrice << gas << data;
if (isCreation())
_s << init;
if (_sig) if (_sig)
_s << vrs.v << vrs.r << vrs.s; _s << vrs.v << vrs.r << vrs.s;
} }

31
libethereum/Transaction.h

@ -21,7 +21,7 @@
#pragma once #pragma once
#include "Common.h" #include "CommonEth.h"
#include "RLP.h" #include "RLP.h"
namespace eth namespace eth
@ -34,7 +34,9 @@ struct Signature
u256 s; u256 s;
}; };
// [ nonce, receiving_address, value, [ data item 0, data item 1 ... data item n ], v, r, s ] // [ nonce, value, receiveAddress, gasPrice, gasDeposit, data, v, r, s ]
// or
// [ nonce, endowment, 0, gasPrice, gasDeposit (for init), body, init, v, r, s ]
struct Transaction struct Transaction
{ {
Transaction() {} Transaction() {}
@ -44,15 +46,22 @@ struct Transaction
bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; } bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; }
bool operator!=(Transaction const& _c) const { return !operator==(_c); } bool operator!=(Transaction const& _c) const { return !operator==(_c); }
u256 nonce; u256 nonce; ///< The transaction-count of the sender.
Address receiveAddress; u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions.
u256 value; Address receiveAddress; ///< The receiving address of the transaction.
u256s data; u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS.
Signature vrs; u256 gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended.
Address safeSender() const noexcept; bytes data; ///< The data associated with the transaction, or the main body if it's a creation transaction.
Address sender() const; bytes init; ///< The initialisation associated with the transaction.
void sign(Secret _priv);
Signature vrs; ///< The signature of the transaction. Encodes the sender.
Address safeSender() const noexcept; ///< Like sender() but will never throw.
Address sender() const; ///< Determine the sender of the transaction from the signature (and hash).
void sign(Secret _priv); ///< Sign the transaction.
bool isCreation() const { return !receiveAddress; }
static h256 kFromMessage(h256 _msg, h256 _priv); static h256 kFromMessage(h256 _msg, h256 _priv);
@ -73,7 +82,7 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t)
else else
_out << "[CREATE]"; _out << "[CREATE]";
_out << "/" << _t.nonce << "*" << _t.value; _out << "/" << _t.nonce << "$" << _t.value << "+" << _t.gas << "@" << _t.gasPrice;
Address s; Address s;
try try
{ {

1
libethereum/TransactionQueue.cpp

@ -19,6 +19,7 @@
* @date 2014 * @date 2014
*/ */
#include "Log.h"
#include "Transaction.h" #include "Transaction.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
using namespace std; using namespace std;

16
libethereum/TrieDB.h

@ -23,8 +23,9 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <leveldb/db.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "CommonEth.h"
#include "Log.h"
#include "TrieCommon.h" #include "TrieCommon.h"
namespace ldb = leveldb; namespace ldb = leveldb;
@ -54,7 +55,7 @@ inline std::ostream& operator<<(std::ostream& _out, BasicMap const& _m)
{ {
_out << i.first << ": "; _out << i.first << ": ";
_out << RLP(i.second); _out << RLP(i.second);
_out << " " << asHex(i.second); _out << " " << toHex(i.second);
_out << std::endl; _out << std::endl;
} }
return _out; return _out;
@ -82,11 +83,6 @@ private:
ldb::WriteOptions m_writeOptions; ldb::WriteOptions m_writeOptions;
}; };
#if WIN32
#pragma warning(push)
#pragma warning(disable:4100) // disable warnings so it compiles
#endif
extern const h256 c_shaNull; extern const h256 c_shaNull;
/** /**
@ -177,7 +173,7 @@ public:
} }
if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17))) if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17)))
{ {
cdebug << b.rlp.size() << asHex(b.rlp); cdebug << b.rlp.size() << toHex(b.rlp);
cdebug << rlp; cdebug << rlp;
auto c = rlp.itemCount(); auto c = rlp.itemCount();
cdebug << c; cdebug << c;
@ -337,10 +333,6 @@ std::ostream& operator<<(std::ostream& _out, GenericTrieDB<DB> const& _db)
return _out; return _out;
} }
#if WIN32
#pragma warning(pop)
#endif
template <class KeyType, class DB> template <class KeyType, class DB>
class TrieDB: public GenericTrieDB<DB> class TrieDB: public GenericTrieDB<DB>
{ {

1
libethereum/UPnP.cpp

@ -26,6 +26,7 @@
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnpcommands.h>
#include "Common.h" #include "Common.h"
#include "Log.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "UPnP.h" #include "UPnP.h"
using namespace std; using namespace std;

30
libethereum/VM.cpp

@ -21,38 +21,12 @@
#include "VM.h" #include "VM.h"
#include <secp256k1.h>
#include <boost/filesystem.hpp>
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include <ctime>
#include <random>
#include "BlockChain.h"
#include "Instruction.h"
#include "Exceptions.h"
#include "Dagger.h"
#include "Defaults.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
VM::VM() void VM::reset(u256 _gas)
{
reset();
}
void VM::reset()
{ {
m_gas = _gas;
m_curPC = 0; m_curPC = 0;
m_nextPC = 1; m_nextPC = 1;
m_stepCount = 0; m_stepCount = 0;

568
libethereum/VM.h

@ -22,21 +22,7 @@
#pragma once #pragma once
#include <unordered_map> #include <unordered_map>
#include <secp256k1.h> #include "CommonEth.h"
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include "Common.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "FeeStructure.h" #include "FeeStructure.h"
#include "Instruction.h" #include "Instruction.h"
@ -56,6 +42,9 @@ inline Address asAddress(u256 _item)
inline u256 fromAddress(Address _a) inline u256 fromAddress(Address _a)
{ {
return (u160)_a; return (u160)_a;
// h256 ret;
// memcpy(&ret, &_a, sizeof(_a));
// return ret;
} }
/** /**
@ -66,21 +55,24 @@ class VM
public: public:
/// Construct VM object. /// Construct VM object.
VM(); explicit VM(u256 _gas = 0) { reset(_gas); }
void reset(); void reset(u256 _gas = 0);
template <class Ext> template <class Ext>
void go(Ext& _ext, uint64_t _steps = (uint64_t)-1); bytesConstRef go(Ext& _ext, uint64_t _steps = (uint64_t)-1);
void require(u256 _n) { if (m_stack.size() < _n) throw StackTooSmall(_n, m_stack.size()); } void require(u256 _n) { if (m_stack.size() < _n) throw StackTooSmall(_n, m_stack.size()); }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 runFee() const { return m_runFee; } u256 runFee() const { return m_runFee; }
u256 gas() const { return m_gas; }
private: private:
u256 m_gas = 0;
u256 m_curPC = 0; u256 m_curPC = 0;
u256 m_nextPC = 1; u256 m_nextPC = 1;
uint64_t m_stepCount = 0; uint64_t m_stepCount = 0;
std::map<u256, u256> m_temp; bytes m_temp;
std::vector<u256> m_stack; std::vector<u256> m_stack;
u256 m_runFee = 0; u256 m_runFee = 0;
}; };
@ -88,57 +80,109 @@ private:
} }
// INLINE: // INLINE:
template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps) template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
{ {
for (bool stopped = false; !stopped && _steps--; m_curPC = m_nextPC, m_nextPC = m_curPC + 1) for (bool stopped = false; !stopped && _steps--; m_curPC = m_nextPC, m_nextPC = m_curPC + 1)
{ {
m_stepCount++; m_stepCount++;
// INSTRUCTION... // INSTRUCTION...
auto rawInst = _ext.store(m_curPC); Instruction inst = (Instruction)_ext.getCode(m_curPC);
if (rawInst > 0xff)
throw BadInstruction();
Instruction inst = (Instruction)(uint8_t)rawInst;
// FEES... // FEES...
bigint runFee = m_stepCount > 16 ? _ext.fees.m_stepFee : 0; bigint runGas = c_stepGas;
bigint storeCostDelta = 0; unsigned newTempSize = (unsigned)m_temp.size();
switch (inst) switch (inst)
{ {
case Instruction::STOP:
runGas = 0;
break;
case Instruction::SSTORE: case Instruction::SSTORE:
require(2); require(2);
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
storeCostDelta += _ext.fees.m_memoryFee; runGas = c_sstoreGas * 2;
if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
storeCostDelta -= _ext.fees.m_memoryFee; runGas = 0;
// continue on to... else
runGas = c_sstoreGas;
break;
case Instruction::SLOAD: case Instruction::SLOAD:
runFee += _ext.fees.m_dataFee; runGas += c_sloadGas;
break;
// These all operate on memory and therefore potentially expand it:
case Instruction::MSTORE:
require(2);
newTempSize = (unsigned)m_stack.back() + 32;
break;
case Instruction::MSTORE8:
require(2);
newTempSize = (unsigned)m_stack.back() + 1;
break;
case Instruction::MLOAD:
require(1);
newTempSize = (unsigned)m_stack.back() + 32;
break;
case Instruction::RETURN:
require(2);
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2];
break;
case Instruction::SHA3:
require(2);
runGas = c_sha3Gas;
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2];
break; break;
case Instruction::EXTRO:
case Instruction::BALANCE: case Instruction::BALANCE:
runFee += _ext.fees.m_extroFee; runGas = c_balanceGas;
break; break;
case Instruction::MKTX: case Instruction::CALL:
runFee += _ext.fees.m_txFee; require(7);
runGas = c_callGas + (unsigned)m_stack[m_stack.size() - 3];
newTempSize = std::max((unsigned)m_stack[m_stack.size() - 6] + (unsigned)m_stack[m_stack.size() - 7], (unsigned)m_stack[m_stack.size() - 4] + (unsigned)m_stack[m_stack.size() - 5]);
break; break;
case Instruction::SHA256: case Instruction::CREATE:
case Instruction::RIPEMD160: {
case Instruction::ECMUL: require(3);
case Instruction::ECADD:
case Instruction::ECSIGN: u256 gas = (unsigned)m_stack[m_stack.size() - 1];
case Instruction::ECRECOVER: unsigned inOff = (unsigned)m_stack[m_stack.size() - 2];
case Instruction::ECVALID: unsigned inSize = (unsigned)m_stack[m_stack.size() - 3];
runFee += _ext.fees.m_cryptoFee; newTempSize = inOff + inSize;
unsigned wc = std::min(inSize / 32 * 32 + inOff, (unsigned)m_temp.size());
unsigned nonZero = 0;
for (unsigned i = inOff; i < wc; i += 32)
if (!!*(h256*)(m_temp.data() + inOff))
nonZero++;
runGas += c_createGas + nonZero * c_sstoreGas + gas;
break; break;
}
default: default:
break; break;
} }
_ext.payFee(runFee + storeCostDelta);
m_runFee += (u256)runFee; newTempSize = (newTempSize + 31) / 32 * 32;
if (newTempSize > m_temp.size())
runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32;
if (m_gas < runGas)
{
// Out of gas!
m_gas = 0;
throw OutOfGas();
}
m_gas = (u256)((bigint)m_gas - runGas);
if (newTempSize > m_temp.size())
m_temp.resize(newTempSize);
// EXECUTE... // EXECUTE...
switch (inst) switch (inst)
@ -162,21 +206,29 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
break; break;
case Instruction::DIV: case Instruction::DIV:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return bytesConstRef();
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2]; m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::SDIV: case Instruction::SDIV:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return bytesConstRef();
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2]; (s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::MOD: case Instruction::MOD:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return bytesConstRef();
m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2]; m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::SMOD: case Instruction::SMOD:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return bytesConstRef();
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2]; (s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
@ -201,21 +253,11 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::LE:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() <= m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::GT: case Instruction::GT:
require(2); require(2);
m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0; m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::GE:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() >= m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::EQ: case Instruction::EQ:
require(2); require(2);
m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
@ -225,223 +267,130 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
require(1); require(1);
m_stack.back() = m_stack.back() ? 0 : 1; m_stack.back() = m_stack.back() ? 0 : 1;
break; break;
case Instruction::MYADDRESS: case Instruction::AND:
m_stack.push_back(fromAddress(_ext.myAddress)); require(2);
break; m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2];
case Instruction::TXSENDER:
m_stack.push_back(fromAddress(_ext.txSender));
break;
case Instruction::TXVALUE:
m_stack.push_back(_ext.txValue);
break;
case Instruction::TXDATAN:
m_stack.push_back(_ext.txData.size());
break;
case Instruction::TXDATA:
require(1);
m_stack.back() = m_stack.back() < _ext.txData.size() ? _ext.txData[(uint)m_stack.back()] : 0;
break;
case Instruction::BLK_PREVHASH:
m_stack.push_back(_ext.previousBlock.hash);
break;
case Instruction::BLK_COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
break;
case Instruction::BLK_TIMESTAMP:
m_stack.push_back(_ext.currentBlock.timestamp);
break;
case Instruction::BLK_NUMBER:
m_stack.push_back(_ext.currentNumber);
break;
case Instruction::BLK_DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty);
break;
case Instruction::BLK_NONCE:
m_stack.push_back(_ext.previousBlock.nonce);
break;
case Instruction::BASEFEE:
m_stack.push_back(_ext.fees.multiplier());
break;
case Instruction::SHA256:
{
require(1);
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
m_stack.pop_back(); m_stack.pop_back();
CryptoPP::SHA256 digest;
uint i = 0;
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
{
bytes b = toBigEndian(m_stack.back());
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
m_stack.pop_back();
}
std::array<byte, 32> final;
digest.TruncatedFinal(final.data(), 32);
m_stack.push_back(fromBigEndian<u256>(final));
break; break;
} case Instruction::OR:
case Instruction::RIPEMD160: require(2);
{ m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2];
require(1);
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
m_stack.pop_back(); m_stack.pop_back();
CryptoPP::RIPEMD160 digest;
uint i = 0;
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
{
bytes b = toBigEndian(m_stack.back());
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
m_stack.pop_back();
}
std::array<byte, 20> final;
digest.TruncatedFinal(final.data(), 20);
// NOTE: this aligns to right of 256-bit container (low-order bytes).
// This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
m_stack.push_back((u256)fromBigEndian<u160>(final));
break; break;
} case Instruction::XOR:
case Instruction::ECMUL: require(2);
{ m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2];
// ECMUL - pops three items.
// If (S[-2],S[-1]) are a valid point in secp256k1, including both coordinates being less than P, pushes (S[-1],S[-2]) * S[-3], using (0,0) as the point at infinity.
// Otherwise, pushes (0,0).
require(3);
bytes pub(1, 4);
pub += toBigEndian(m_stack[m_stack.size() - 2]);
pub += toBigEndian(m_stack.back());
m_stack.pop_back();
m_stack.pop_back();
bytes x = toBigEndian(m_stack.back());
m_stack.pop_back(); m_stack.pop_back();
if (secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size())) // TODO: Check both are less than P.
{
secp256k1_ecdsa_pubkey_tweak_mul(pub.data(), (int)pub.size(), x.data());
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32)));
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32)));
}
else
{
m_stack.push_back(0);
m_stack.push_back(0);
}
break; break;
} case Instruction::BYTE:
case Instruction::ECADD: require(2);
{ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] < 32 ? (m_stack[m_stack.size() - 2] >> (uint)(31 - m_stack.back())) & 0xff : 0;
// ECADD - pops four items and pushes (S[-4],S[-3]) + (S[-2],S[-1]) if both points are valid, otherwise (0,0).
require(4);
bytes pub(1, 4);
pub += toBigEndian(m_stack[m_stack.size() - 2]);
pub += toBigEndian(m_stack.back());
m_stack.pop_back();
m_stack.pop_back();
bytes tweak(1, 4);
tweak += toBigEndian(m_stack[m_stack.size() - 2]);
tweak += toBigEndian(m_stack.back());
m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
if (secp256k1_ecdsa_pubkey_verify(pub.data(),(int) pub.size()) && secp256k1_ecdsa_pubkey_verify(tweak.data(),(int) tweak.size()))
{
secp256k1_ecdsa_pubkey_tweak_add(pub.data(), (int)pub.size(), tweak.data());
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32)));
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32)));
}
else
{
m_stack.push_back(0);
m_stack.push_back(0);
}
break; break;
} case Instruction::SHA3:
case Instruction::ECSIGN:
{ {
require(2); require(2);
bytes sig(64); unsigned inOff = (unsigned)m_stack.back();
int v = 0;
u256 msg = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
u256 priv = m_stack.back(); unsigned inSize = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
bytes nonce = toBigEndian(Transaction::kFromMessage(msg, priv)); m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize)));
if (!secp256k1_ecdsa_sign_compact(toBigEndian(msg).data(), 64, sig.data(), toBigEndian(priv).data(), nonce.data(), &v))
throw InvalidSignature();
m_stack.push_back(v + 27);
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(0, 32)));
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(32)));
break; break;
} }
case Instruction::ECRECOVER: case Instruction::ADDRESS:
{ m_stack.push_back(fromAddress(_ext.myAddress));
require(4);
bytes sig = toBigEndian(m_stack[m_stack.size() - 2]) + toBigEndian(m_stack.back());
m_stack.pop_back();
m_stack.pop_back();
int v = (int)m_stack.back();
m_stack.pop_back();
bytes msg = toBigEndian(m_stack.back());
m_stack.pop_back();
byte pubkey[65];
int pubkeylen = 65;
if (secp256k1_ecdsa_recover_compact(msg.data(), (int)msg.size(), sig.data(), pubkey, &pubkeylen, 0, v - 27))
{
m_stack.push_back(0);
m_stack.push_back(0);
}
else
{
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[1], 32)));
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[33], 32)));
}
break; break;
} case Instruction::ORIGIN:
case Instruction::ECVALID: m_stack.push_back(fromAddress(_ext.origin));
break;
case Instruction::BALANCE:
{ {
require(2); require(1);
bytes pub(1, 4); m_stack.back() = _ext.balance(asAddress(m_stack.back()));
pub += toBigEndian(m_stack[m_stack.size() - 2]);
pub += toBigEndian(m_stack.back());
m_stack.pop_back();
m_stack.pop_back();
m_stack.back() = secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size()) ? 1 : 0;
break; break;
} }
case Instruction::SHA3: case Instruction::CALLER:
m_stack.push_back(fromAddress(_ext.caller));
break;
case Instruction::CALLVALUE:
m_stack.push_back(_ext.value);
break;
case Instruction::CALLDATALOAD:
{ {
require(1); require(1);
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); if ((unsigned)m_stack.back() + 32 < _ext.data.size())
m_stack.pop_back(); m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
else
CryptoPP::SHA3_256 digest;
uint i = 0;
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
{ {
bytes b = toBigEndian(m_stack.back()); h256 r;
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32 for (unsigned i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + 32, j = 0; i < e; ++i, ++j)
m_stack.pop_back(); r[j] = i < _ext.data.size() ? _ext.data[i] : 0;
m_stack.back() = (u256)r;
} }
std::array<byte, 32> final;
digest.TruncatedFinal(final.data(), 32);
m_stack.push_back(fromBigEndian<u256>(final));
break; break;
} }
case Instruction::PUSH: case Instruction::CALLDATASIZE:
m_stack.push_back(_ext.data.size());
break;
case Instruction::GASPRICE:
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::PREVHASH:
m_stack.push_back(_ext.previousBlock.hash);
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
break;
case Instruction::TIMESTAMP:
m_stack.push_back(_ext.currentBlock.timestamp);
break;
case Instruction::NUMBER:
m_stack.push_back(_ext.currentNumber);
break;
case Instruction::DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty);
break;
case Instruction::GASLIMIT:
m_stack.push_back(1000000);
break;
case Instruction::PUSH1:
case Instruction::PUSH2:
case Instruction::PUSH3:
case Instruction::PUSH4:
case Instruction::PUSH5:
case Instruction::PUSH6:
case Instruction::PUSH7:
case Instruction::PUSH8:
case Instruction::PUSH9:
case Instruction::PUSH10:
case Instruction::PUSH11:
case Instruction::PUSH12:
case Instruction::PUSH13:
case Instruction::PUSH14:
case Instruction::PUSH15:
case Instruction::PUSH16:
case Instruction::PUSH17:
case Instruction::PUSH18:
case Instruction::PUSH19:
case Instruction::PUSH20:
case Instruction::PUSH21:
case Instruction::PUSH22:
case Instruction::PUSH23:
case Instruction::PUSH24:
case Instruction::PUSH25:
case Instruction::PUSH26:
case Instruction::PUSH27:
case Instruction::PUSH28:
case Instruction::PUSH29:
case Instruction::PUSH30:
case Instruction::PUSH31:
case Instruction::PUSH32:
{ {
m_stack.push_back(_ext.store(m_curPC + 1)); int i = (int)inst - (int)Instruction::PUSH1 + 1;
m_nextPC = m_curPC + 2; m_nextPC = m_curPC + 1;
m_stack.push_back(0);
for (; i--; m_nextPC++)
m_stack.back() = (m_stack.back() << 8) | _ext.getCode(m_nextPC);
break; break;
} }
case Instruction::POP: case Instruction::POP:
@ -484,29 +433,21 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::MLOAD: case Instruction::MLOAD:
{ {
require(1); require(1);
#ifdef __clang__ m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back());
auto mFinder = m_temp.find(m_stack.back());
if (mFinder != m_temp.end())
m_stack.back() = mFinder->second;
else
m_stack.back() = 0;
#else
m_stack.back() = m_temp[m_stack.back()];
#endif
break; break;
} }
case Instruction::MSTORE: case Instruction::MSTORE:
{ {
require(2); require(2);
#ifdef __clang__ *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2];
auto mFinder = m_temp.find(m_stack.back()); m_stack.pop_back();
if (mFinder == m_temp.end()) m_stack.pop_back();
m_temp.insert(std::make_pair(m_stack.back(), m_stack[m_stack.size() - 2])); break;
else }
mFinder->second = m_stack[m_stack.size() - 2]; case Instruction::MSTORE8:
#else {
m_temp[m_stack.back()] = m_stack[m_stack.size() - 2]; require(2);
#endif m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff);
m_stack.pop_back(); m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
@ -521,60 +462,96 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
m_stack.pop_back(); m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::JMP: case Instruction::JUMP:
require(1); require(1);
m_nextPC = m_stack.back(); m_nextPC = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::JMPI: case Instruction::JUMPI:
require(2); require(2);
if (m_stack.back()) if (m_stack[m_stack.size() - 2])
m_nextPC = m_stack[m_stack.size() - 2]; m_nextPC = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::IND: case Instruction::PC:
m_stack.push_back(m_curPC); m_stack.push_back(m_curPC);
break; break;
case Instruction::EXTRO: case Instruction::MEMSIZE:
{ m_stack.push_back(m_temp.size());
require(2);
auto memoryAddress = m_stack.back();
m_stack.pop_back();
Address contractAddress = asAddress(m_stack.back());
m_stack.back() = _ext.extro(contractAddress, memoryAddress);
break; break;
} case Instruction::GAS:
case Instruction::BALANCE: m_stack.push_back(m_gas);
break;
case Instruction::CREATE:
{ {
require(1); require(5);
m_stack.back() = _ext.balance(asAddress(m_stack.back()));
u256 endowment = m_stack.back();
m_stack.pop_back();
unsigned codeOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned codeSize = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned initOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned initSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= endowment)
{
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + codeOff, codeSize), bytesConstRef(m_temp.data() + initOff, initSize)));
}
else
m_stack.push_back(0);
break; break;
} }
case Instruction::MKTX: case Instruction::CALL:
{ {
require(3); require(7);
Transaction t; u160 receiveAddress = asAddress(m_stack.back());
t.receiveAddress = asAddress(m_stack.back()); m_stack.pop_back();
u256 value = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
t.value = m_stack.back(); u256 gas = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
auto itemCount = m_stack.back(); unsigned inOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned inSize = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
if (m_stack.size() < itemCount) unsigned outOff = (unsigned)m_stack.back();
throw OperandOutOfRange(0, m_stack.size(), itemCount); m_stack.pop_back();
t.data.reserve((uint)itemCount); unsigned outSize = (unsigned)m_stack.back();
for (auto i = 0; i < itemCount; ++i) m_stack.pop_back();
if (!gas)
{ {
t.data.push_back(m_stack.back()); gas = m_gas;
m_stack.pop_back(); m_gas = 0;
}
if (_ext.balance(_ext.myAddress) >= value)
{
_ext.subBalance(value);
m_stack.push_back(_ext.call(receiveAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), &gas, bytesRef(m_temp.data() + outOff, outSize)));
} }
_ext.mktx(t); m_gas += gas;
break; break;
} }
case Instruction::RETURN:
{
require(2);
unsigned b = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned s = (unsigned)m_stack.back();
m_stack.pop_back();
return bytesConstRef(m_temp.data() + b, s);
}
case Instruction::SUICIDE: case Instruction::SUICIDE:
{ {
require(1); require(1);
@ -583,12 +560,13 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
// ...follow through to... // ...follow through to...
} }
case Instruction::STOP: case Instruction::STOP:
return; return bytesConstRef();
default: default:
throw BadInstruction(); throw BadInstruction();
} }
} }
if (_steps == (unsigned)-1) if (_steps == (unsigned)-1)
throw StepsDone(); throw StepsDone();
return bytesConstRef();
} }

11
libethereum/vector_ref.h

@ -5,14 +5,10 @@
#include <vector> #include <vector>
#include <string> #include <string>
#if WIN32
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4267) #pragma warning(disable: 4100 4267)
#endif
#include <leveldb/db.h> #include <leveldb/db.h>
#if WIN32
#pragma warning(pop) #pragma warning(pop)
#endif
namespace eth namespace eth
{ {
@ -23,6 +19,7 @@ class vector_ref
public: public:
typedef _T value_type; typedef _T value_type;
typedef _T element_type; typedef _T element_type;
typedef typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type mutable_value_type;
vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(): m_data(nullptr), m_count(0) {}
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
@ -33,8 +30,8 @@ public:
explicit operator bool() const { return m_data && m_count; } explicit operator bool() const { return m_data && m_count; }
bool contentsEqual(std::vector<_T> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
std::vector<_T> toVector() const { return std::vector<_T>(m_data, m_data + m_count); } std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); }
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>((unsigned char const*)m_data, m_data + m_count * sizeof(_T)); } std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>((unsigned char const*)m_data, m_data + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count); }
template <class _T2> operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); } template <class _T2> operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); }

8
package.sh

@ -1,8 +0,0 @@
#!/bin/bash
set -e
rm -f ../cpp-ethereum_*_source.changes
debuild -S -sa
cd ..
dput -f ppa:ethereum/ethereum cpp-ethereum_*_source.changes

74
release.sh

@ -1,74 +0,0 @@
#!/bin/bash
dist="saucy"
version=$(grep "define ETH_VERSION" libethereum/Common.h | cut -d ' ' -f 3)
branch="$(git branch | grep \* | cut -c 3-)"
if [[ ! "$1" == "" ]]; then
version=$1
fi
if [[ ! "$3" == "" ]]; then
if [[ ! "$4" == "" ]]; then
dist=$4
fi
if [[ "$2" == "-i" ]]; then
# increment current debian release only
# new version ./release VERSION -i MESSAGE DIST
debchange -i -p "$3" -D "$dist"
git commit -a -m "$3"
else
# new version ./release VERSION DEB-VERSION MESSAGE DIST
debchange -v $version-$2 -p "$3" -D "$dist"
git commit -a -m "$3"
fi
fi
opwd=`pwd`
cd /tmp
echo Checking out...
git clone $opwd
cd cpp-ethereum
git checkout "$branch"
archdir="cpp-ethereum-$version"
archfile="$archdir.tar.bz2"
echo Making BuildInfo...
mkdir build
cd build
cmake ..
cd ..
cp build/BuildInfo.h .
rm -rf build
echo Cleaning backup files...
find . | grep \~ | xargs rm -f
echo Cleaning others...
rm release.sh
echo Cleaning versioning...
rm -rf .git .gitignore
echo Renaming directory...
cd ..
rm -rf $archdir
mv cpp-ethereum $archdir
echo Creating archive...
tar c $archdir | bzip2 -- > $archfile
shasum $archfile
[[ ! "$version" == "" ]] && ln -sf $archfile "cpp-ethereum_$version.orig.tar.bz2"
echo Packaging...
cd "$archdir"
./package.sh
echo Cleaning up...
rm -rf /tmp/$archdir
mv /tmp/$archfile ~
echo Done.

2
test/CMakeLists.txt

@ -21,6 +21,8 @@ if (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(testeth boost_filesystem-mt-s) target_link_libraries(testeth boost_filesystem-mt-s)
target_link_libraries(testeth boost_thread_win32-mt-s) target_link_libraries(testeth boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else () else ()
target_link_libraries(testeth ${CRYPTOPP_LIBRARIES}) target_link_libraries(testeth ${CRYPTOPP_LIBRARIES})
target_link_libraries(testeth boost_system) target_link_libraries(testeth boost_system)

32
test/JsonSpiritHeaders.h

@ -0,0 +1,32 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JsonSpiritHeaders.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2014
*/
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#pragma GCC diagnostic pop
#pragma warning(pop)

15
libethereum/MemTrie.cpp → test/MemTrie.cpp

@ -19,9 +19,10 @@
* @date 2014 * @date 2014
*/ */
#include "Common.h"
#include "TrieCommon.h"
#include "MemTrie.h" #include "MemTrie.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -147,7 +148,7 @@ public:
assert(m_value.size()); assert(m_value.size());
std::cerr << _indent; std::cerr << _indent;
if (m_ext.size()) if (m_ext.size())
std::cerr << asHex(m_ext, 1) << ": "; std::cerr << toHex(m_ext, 1) << ": ";
else else
std::cerr << "@: "; std::cerr << "@: ";
std::cerr << m_value << std::endl; std::cerr << m_value << std::endl;
@ -174,7 +175,7 @@ public:
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
virtual void debugPrintBody(std::string const& _indent) const virtual void debugPrintBody(std::string const& _indent) const
{ {
std::cerr << _indent << asHex(m_ext, 1) << ": "; std::cerr << _indent << toHex(m_ext, 1) << ": ";
m_next->debugPrint(_indent + " "); m_next->debugPrint(_indent + " ");
} }
#endif #endif
@ -454,7 +455,7 @@ std::string const& MemTrie::at(std::string const& _key) const
{ {
if (!m_root) if (!m_root)
return c_nullString; return c_nullString;
auto h = toHex(_key); auto h = asNibbles(_key);
return m_root->at(bytesConstRef(&h)); return m_root->at(bytesConstRef(&h));
} }
@ -462,7 +463,7 @@ void MemTrie::insert(std::string const& _key, std::string const& _value)
{ {
if (_value.empty()) if (_value.empty())
remove(_key); remove(_key);
auto h = toHex(_key); auto h = asNibbles(_key);
m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value); m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value);
} }
@ -470,7 +471,7 @@ void MemTrie::remove(std::string const& _key)
{ {
if (m_root) if (m_root)
{ {
auto h = toHex(_key); auto h = asNibbles(_key);
m_root = m_root->remove(&h); m_root = m_root->remove(&h);
} }
} }

3
libethereum/MemTrie.h → test/MemTrie.h

@ -21,7 +21,8 @@
#pragma once #pragma once
#include "Common.h" #include <Common.h>
#include <FixedHash.h>
namespace eth namespace eth
{ {

49
test/TestHelper.cpp

@ -0,0 +1,49 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TestHelper.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
*/
#include <thread>
#include <chrono>
#include <Client.h>
#include "TestHelper.h"
namespace eth
{
void mine(Client& c, int numBlocks)
{
auto startBlock = c.blockChain().details().number;
c.startMining();
while(c.blockChain().details().number < startBlock + numBlocks)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
c.stopMining();
}
void connectClients(Client& c1, Client& c2)
{
short c1Port = 20000;
short c2Port = 21000;
c1.startNetwork(c1Port);
c2.startNetwork(c2Port);
c2.connect("127.0.0.1", c1Port);
}
}

30
test/TestHelper.h

@ -0,0 +1,30 @@
/*
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 TestHelper.h
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
*/
#pragma once
namespace eth
{
void mine(Client& c, int numBlocks);
void connectClients(Client& c1, Client& c2);
}

15
libethereum/TrieHash.cpp → test/TrieHash.cpp

@ -19,9 +19,10 @@
* @date 2014 * @date 2014
*/ */
#include "Common.h"
#include "TrieCommon.h"
#include "TrieHash.h" #include "TrieHash.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -58,7 +59,7 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
_rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second; _rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second;
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
if (g_hashDebug) if (g_hashDebug)
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha3(_rlp.out()) << std::endl; std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha3(_rlp.out()) << std::endl;
#endif #endif
} }
else else
@ -79,7 +80,7 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
// if they all have the same next nibble, we also want a pair. // if they all have the same next nibble, we also want a pair.
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
if (g_hashDebug) if (g_hashDebug)
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl; std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl;
#endif #endif
_rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre); _rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre);
hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp); hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp);
@ -162,7 +163,7 @@ h256 hash256(StringMap const& _s)
return h256(); return h256();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
RLPStream s; RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out()); return sha3(s.out());
@ -175,7 +176,7 @@ bytes rlp256(StringMap const& _s)
return bytes(); return bytes();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
RLPStream s; RLPStream s;
hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return s.out(); return s.out();
@ -188,7 +189,7 @@ h256 hash256(u256Map const& _s)
return h256(); return h256();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(toBigEndianString(i->first))] = asString(rlp(i->second)); hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second));
RLPStream s; RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out()); return sha3(s.out());

3
libethereum/TrieHash.h → test/TrieHash.h

@ -21,7 +21,8 @@
#pragma once #pragma once
#include "Common.h" #include <Common.h>
#include <FixedHash.h>
namespace eth namespace eth
{ {

24
test/boostTest.cpp

@ -0,0 +1,24 @@
/*
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 boostTest.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
* Stub for generating main boost.test module.
*/
#define BOOST_TEST_MODULE EthereumTests
#include <boost/test/included/unit_test.hpp>

38
test/crypto.cpp

@ -24,6 +24,7 @@
#include <secp256k1.h> #include <secp256k1.h>
#include <Common.h> #include <Common.h>
#include <RLP.h> #include <RLP.h>
#include <Log.h>
#include <Transaction.h> #include <Transaction.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -33,21 +34,20 @@ int cryptoTest()
cnote << "Testing Crypto..."; cnote << "Testing Crypto...";
secp256k1_start(); secp256k1_start();
KeyPair p(Secret(fromUserHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
assert(p.pub() == Public(fromUserHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
assert(p.address() == Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
{ {
Transaction t; Transaction t;
t.nonce = 0; t.nonce = 0;
t.receiveAddress = h160(fromUserHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
t.data = u256s();
cnote << RLP(t.rlp(false)); cnote << RLP(t.rlp(false));
cnote << asHex(t.rlp(false)); cnote << toHex(t.rlp(false));
cnote << t.sha3(false); cnote << t.sha3(false);
t.sign(p.secret()); t.sign(p.secret());
cnote << RLP(t.rlp(true)); cnote << RLP(t.rlp(true));
cnote << asHex(t.rlp(true)); cnote << toHex(t.rlp(true));
cnote << t.sha3(true); cnote << t.sha3(true);
assert(t.sender() == p.address()); assert(t.sender() == p.address());
} }
@ -55,7 +55,7 @@ int cryptoTest()
#if 0 #if 0
// Test transaction. // Test transaction.
bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d"); bytes tx = fromHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");
cout << "TX: " << RLP(tx) << endl; cout << "TX: " << RLP(tx) << endl;
Transaction t2(tx); Transaction t2(tx);
@ -69,13 +69,13 @@ int cryptoTest()
t.receiveAddress = toAddress(sha3("123")); t.receiveAddress = toAddress(sha3("123"));
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);
cout << "SIG: " << sig64.size() << " " << asHex(sig64) << " " << t.vrs.v << endl; cout << "SIG: " << sig64.size() << " " << toHex(sig64) << " " << t.vrs.v << endl;
auto msg = t.rlp(false); auto msg = t.rlp(false);
cout << "TX w/o SIG: " << RLP(msg) << endl; cout << "TX w/o SIG: " << RLP(msg) << endl;
cout << "RLP(TX w/o SIG): " << asHex(t.rlpString(false)) << endl; cout << "RLP(TX w/o SIG): " << toHex(t.rlpString(false)) << endl;
std::string hmsg = sha3(t.rlpString(false), false); std::string hmsg = sha3(t.rlpString(false), false);
cout << "SHA256(RLP(TX w/o SIG)): 0x" << asHex(hmsg) << endl; cout << "SHA256(RLP(TX w/o SIG)): 0x" << toHex(hmsg) << endl;
bytes privkey = sha3Bytes("123"); bytes privkey = sha3Bytes("123");
@ -84,12 +84,12 @@ int cryptoTest()
int pubkeylen = 65; int pubkeylen = 65;
int ret = secp256k1_ecdsa_seckey_verify(privkey.data()); int ret = secp256k1_ecdsa_seckey_verify(privkey.data());
cout << "SEC: " << dec << ret << " " << asHex(privkey) << endl; cout << "SEC: " << dec << ret << " " << toHex(privkey) << endl;
ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, privkey.data(), 1); ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, privkey.data(), 1);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
int good = secp256k1_ecdsa_pubkey_verify(pubkey.data(), (int)pubkey.size()); int good = secp256k1_ecdsa_pubkey_verify(pubkey.data(), (int)pubkey.size());
cout << "PUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << (good ? " GOOD" : " BAD") << endl; cout << "PUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << (good ? " GOOD" : " BAD") << endl;
} }
// Test roundtrip... // Test roundtrip...
@ -97,17 +97,17 @@ int cryptoTest()
bytes sig(64); bytes sig(64);
u256 nonce = 0; u256 nonce = 0;
int v = 0; int v = 0;
cout << asHex(hmsg) << endl; cout << toHex(hmsg) << endl;
cout << asHex(privkey) << endl; cout << toHex(privkey) << endl;
cout << hex << nonce << dec << endl; cout << hex << nonce << dec << endl;
int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), (int)hmsg.size(), sig.data(), privkey.data(), (byte const*)&nonce, &v); int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), (int)hmsg.size(), sig.data(), privkey.data(), (byte const*)&nonce, &v);
cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << asHex(sig) << " " << v << endl; cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << toHex(sig) << " " << v << endl;
bytes pubkey(65); bytes pubkey(65);
int pubkeylen = 65; int pubkeylen = 65;
ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 0, v); ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 0, v);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
cout << "MYREC: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; cout << "MYREC: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl;
} }
{ {
@ -115,8 +115,8 @@ int cryptoTest()
int pubkeylen = 65; int pubkeylen = 65;
int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27); int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl;
cout << "SENDER: " << hex << low160(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; cout << "SENDER: " << hex << toAddress(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl;
} }
#endif #endif
return 0; return 0;

1
test/dagger.cpp

@ -21,6 +21,7 @@
*/ */
#include <chrono> #include <chrono>
#include "Log.h"
#include "Dagger.h" #include "Dagger.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;

56
test/fork.cpp

@ -0,0 +1,56 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file fork.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
* Tests for different forking behavior
*/
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <Client.h>
#include <BlockChain.h>
#include <PeerServer.h>
#include "TestHelper.h"
using namespace std;
using namespace eth;
BOOST_AUTO_TEST_CASE(simple_chain_fork)
{
//start a client and mine a short chain
Client c1("TestClient1", KeyPair::create().address(),
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
mine(c1, 4);
//start another client and mine a longer chain
Client c2("TestClient2", KeyPair::create().address(),
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
mine(c2, 6);
//connect the two clients up to resolve chain
c1.startNetwork(20000);
c2.startNetwork(21000);
c2.connect("127.0.0.1", 20000);
//mine an extra block to cement it
mine(c1, 1);
//check the balances are where they should be
//c1's chain should have been clobbered by c2
BOOST_REQUIRE(c1.state().balance(c1.address()) == 0);
BOOST_REQUIRE(c2.state().balance(c2.address()) > 0);
}

8
test/hexPrefix.cpp

@ -21,9 +21,9 @@
*/ */
#include <fstream> #include <fstream>
#include "../json_spirit/json_spirit_reader_template.h" #include "JsonSpiritHeaders.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include "TrieCommon.h" #include "TrieCommon.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
namespace js = json_spirit; namespace js = json_spirit;
@ -48,11 +48,11 @@ public:
for (auto& i: o["seq"].get_array()) for (auto& i: o["seq"].get_array())
v.push_back((byte)i.get_int()); v.push_back((byte)i.get_int());
auto e = hexPrefixEncode(v, o["term"].get_bool()); auto e = hexPrefixEncode(v, o["term"].get_bool());
if (!o["out"].is_null() && o["out"].get_str() != asHex(e)) if (!o["out"].is_null() && o["out"].get_str() != toHex(e))
{ {
cwarn << "Test failed."; cwarn << "Test failed.";
cwarn << "Test says:" << o["out"].get_str(); cwarn << "Test says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(e); cwarn << "Impl says:" << toHex(e);
passed = false; passed = false;
} }
} }

9
test/main.cpp

@ -20,6 +20,8 @@
* Main test functions. * Main test functions.
*/ */
#include <boost/test/unit_test.hpp>
// TODO: utilise the shared testdata. // TODO: utilise the shared testdata.
int trieTest(); int trieTest();
@ -34,12 +36,12 @@ int peerTest(int argc, char** argv);
#include <BlockInfo.h> #include <BlockInfo.h>
using namespace eth; using namespace eth;
int main(int, char**) BOOST_AUTO_TEST_CASE(basic_tests)
{ {
/* RLPStream s; /* RLPStream s;
BlockInfo::genesis().fillStream(s, false); BlockInfo::genesis().fillStream(s, false);
std::cout << RLP(s.out()) << std::endl; std::cout << RLP(s.out()) << std::endl;
std::cout << asHex(s.out()) << std::endl; std::cout << toHex(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;*/ std::cout << sha3(s.out()) << std::endl;*/
int r = 0; int r = 0;
@ -51,7 +53,6 @@ int main(int, char**)
// r += daggerTest(); // r += daggerTest();
// r += stateTest(); // r += stateTest();
// r += peerTest(argc, argv); // r += peerTest(argc, argv);
assert(!r); BOOST_REQUIRE(!r);
return 0;
} }

51
test/network.cpp

@ -0,0 +1,51 @@
/*
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 network.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
* Basic networking tests
*/
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <Client.h>
#include <BlockChain.h>
#include <PeerServer.h>
#include "TestHelper.h"
using namespace std;
using namespace eth;
BOOST_AUTO_TEST_CASE(listen_port_busy)
{
short port = 20000;
//make use of the port ahead of our client
ba::io_service ioService;
bi::tcp::endpoint endPoint(bi::tcp::v4(), port);
bi::tcp::acceptor acceptor(ioService, endPoint);
acceptor.listen(10);
//prepare client and try to listen on same, used, port
Client c1("TestClient1", KeyPair::create().address(),
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
c1.startNetwork(port);
BOOST_REQUIRE(c1.haveNetwork());
BOOST_REQUIRE(c1.peerServer()->listenPort() != 0);
BOOST_REQUIRE(c1.peerServer()->listenPort() != port);
}

2
test/peer.cpp

@ -24,7 +24,7 @@
#include <thread> #include <thread>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <BlockChain.h> #include <BlockChain.h>
#include <PeerNetwork.h> #include <PeerServer.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
using boost::asio::ip::tcp; using boost::asio::ip::tcp;

8
test/rlp.cpp

@ -21,8 +21,8 @@
*/ */
#include <fstream> #include <fstream>
#include "../json_spirit/json_spirit_reader_template.h" #include "JsonSpiritHeaders.h"
#include "../json_spirit/json_spirit_writer_template.h" #include <Log.h>
#include <RLP.h> #include <RLP.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -67,11 +67,11 @@ public:
cnote << i.first; cnote << i.first;
RLPStream s; RLPStream s;
buildRLP(o["in"], s); buildRLP(o["in"], s);
if (!o["out"].is_null() && o["out"].get_str() != asHex(s.out())) if (!o["out"].is_null() && o["out"].get_str() != toHex(s.out()))
{ {
cwarn << "Test failed."; cwarn << "Test failed.";
cwarn << "Test says:" << o["out"].get_str(); cwarn << "Test says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(s.out()); cwarn << "Impl says:" << toHex(s.out());
passed = false; passed = false;
} }
} }

13
test/trie.cpp

@ -21,12 +21,11 @@
*/ */
#include <fstream> #include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <random> #include <random>
#include <TrieHash.h> #include "JsonSpiritHeaders.h"
#include <TrieDB.h> #include <TrieDB.h>
#include <MemTrie.h> #include "TrieHash.h"
#include "MemTrie.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -61,11 +60,11 @@ public:
t.init(); t.init();
for (auto const& k: ss) for (auto const& k: ss)
t.insert(k.first, k.second); t.insert(k.first, k.second);
if (!o["root"].is_null() && o["root"].get_str() != asHex(t.root().asArray())) if (!o["root"].is_null() && o["root"].get_str() != toHex(t.root().asArray()))
{ {
cwarn << "Test failed on permutation " << j; cwarn << "Test failed on permutation " << j;
cwarn << "Test says:" << o["root"].get_str(); cwarn << "Test says:" << o["root"].get_str();
cwarn << "Impl says:" << asHex(t.root().asArray()); cwarn << "Impl says:" << toHex(t.root().asArray());
passed = false; passed = false;
} }
} }
@ -154,7 +153,7 @@ int trieTest()
t.insert("doe", "reindeer"); t.insert("doe", "reindeer");
cout << hex << t.hash256() << endl; cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl; cout << RLP(t.rlp()) << endl;
cout << asHex(t.rlp()) << endl; cout << toHex(t.rlp()) << endl;
} }
{ {
BasicMap m; BasicMap m;

117
test/txTest.cpp

@ -0,0 +1,117 @@
/*
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 txTest.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
* Simple peer transaction send test.
*/
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <Client.h>
#include <BlockChain.h>
#include <PeerServer.h>
#include "TestHelper.h"
using namespace std;
using namespace eth;
BOOST_AUTO_TEST_CASE(mine_local_simple_tx)
{
KeyPair kp1 = KeyPair::create();
KeyPair kp2 = KeyPair::create();
Client c1("TestClient1", kp1.address(), (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
//mine some blocks so that client 1 has a balance
mine(c1, 1);
auto c1bal = c1.state().balance(kp1.address());
BOOST_REQUIRE(c1bal > 0);
//send c2 some eth from c1
auto txAmount = c1bal / 2u;
auto gasPrice = 10 * szabo;
auto gas = eth::c_callGas;
c1.transact(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice);
//mine some more to include the transaction on chain
mine(c1, 1);
auto c2bal = c1.state().balance(kp2.address());
BOOST_REQUIRE(c2bal > 0);
BOOST_REQUIRE(c2bal == txAmount);
}
BOOST_AUTO_TEST_CASE(mine_and_send_to_peer)
{
KeyPair kp1 = KeyPair::create();
KeyPair kp2 = KeyPair::create();
Client c1("TestClient1", kp1.address(), (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
Client c2("TestClient2", kp2.address(), (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
connectClients(c1, c2);
//mine some blocks so that client 1 has a balance
mine(c1, 1);
auto c1bal = c1.state().balance(kp1.address());
BOOST_REQUIRE(c1bal > 0);
//send c2 some eth from c1
auto txAmount = c1bal / 2u;
auto gasPrice = 10 * szabo;
auto gas = eth::c_callGas;
c1.transact(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice);
//mine some more to include the transaction on chain
mine(c1, 1);
auto c2bal = c2.state().balance(kp2.address());
BOOST_REQUIRE(c2bal > 0);
BOOST_REQUIRE(c2bal == txAmount);
}
BOOST_AUTO_TEST_CASE(mine_and_send_to_peer_fee_check)
{
KeyPair kp1 = KeyPair::create();
KeyPair kp2 = KeyPair::create();
Client c1("TestClient1", kp1.address(), (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
Client c2("TestClient2", kp2.address(), (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
connectClients(c1, c2);
//mine some blocks so that client 1 has a balance
mine(c1, 1);
auto c1StartBalance = c1.state().balance(kp1.address());
auto c2StartBalance = c2.state().balance(kp2.address());
BOOST_REQUIRE(c1StartBalance > 0);
BOOST_REQUIRE(c2StartBalance == 0);
//send c2 some eth from c1
auto txAmount = c1StartBalance / 2u;
auto gasPrice = 10 * szabo;
auto gas = eth::c_callGas;
c1.transact(kp1.secret(), txAmount, c2.address(), bytes(), gas, gasPrice);
//mine some more, this time with second client (so he can get fees from first client's tx)
mine(c2, 1);
auto c1EndBalance = c1.state().balance(kp1.address());
auto c2EndBalance = c2.state().balance(kp2.address());
BOOST_REQUIRE(c1EndBalance > 0);
BOOST_REQUIRE(c1EndBalance == c1StartBalance - txAmount - gasPrice * gas);
BOOST_REQUIRE(c2EndBalance > 0);
}

221
test/vm.cpp

@ -21,12 +21,12 @@
*/ */
#include <fstream> #include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <ExtVMFace.h> #include <ExtVMFace.h>
#include <Transaction.h> #include <Transaction.h>
#include <VM.h> #include <VM.h>
#include <Log.h>
#include <Instruction.h> #include <Instruction.h>
#include "JsonSpiritHeaders.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
using namespace eth; using namespace eth;
@ -39,39 +39,27 @@ class FakeExtVM: public ExtVMFace
public: public:
FakeExtVM() FakeExtVM()
{} {}
FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): FakeExtVM(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber) ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _currentNumber)
{} {}
u256 store(u256 _n) u256 store(u256 _n)
{ {
#ifdef __clang__
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[myAddress];
map<u256, u256> & third = get<3>(address);
auto sFinder = third.find(_n);
if (sFinder != third.end())
return sFinder->second;
else
return 0;
#else
return get<3>(addresses[myAddress])[_n]; return get<3>(addresses[myAddress])[_n];
#endif
} }
void setStore(u256 _n, u256 _v) void setStore(u256 _n, u256 _v)
{ {
#ifdef __clang__
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[myAddress];
map<u256, u256> & third = get<3>(address);
auto sFinder = third.find(_n);
if (sFinder != third.end())
sFinder->second = _v;
else
third.insert(std::make_pair(_n, _v));
#else
get<3>(addresses[myAddress])[_n] = _v; get<3>(addresses[myAddress])[_n] = _v;
#endif
} }
void mktx(Transaction& _t) u256 balance(Address _a) { return get<0>(addresses[_a]); }
void subBalance(u256 _a) { get<0>(addresses[myAddress]) -= _a; }
u256 txCount(Address _a) { return get<1>(addresses[_a]); }
void suicide(Address _a)
{
get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
addresses.erase(myAddress);
}
void transact(Transaction& _t)
{ {
if (get<0>(addresses[myAddress]) >= _t.value) if (get<0>(addresses[myAddress]) >= _t.value)
{ {
@ -81,63 +69,57 @@ public:
txs.push_back(_t); txs.push_back(_t);
} }
} }
u256 balance(Address _a) { return get<0>(addresses[_a]); } h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); }
u256 txCount(Address _a) { return get<1>(addresses[_a]); }
u256 extro(Address _a, u256 _pos)
{ {
#ifdef __clang__ Transaction t;
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a]; t.value = _endowment;
map<u256, u256> & third = get<3>(address); t.gasPrice = gasPrice;
auto sFinder = third.find(_pos); t.gas = *_gas;
if (sFinder != third.end()) t.data = _code.toBytes();
return sFinder->second; t.init = _init.toBytes();
else txs.push_back(t);
return 0; return right160(t.sha3(false));
#else
return get<3>(addresses[_a])[_pos];
#endif
} }
u256 extroPrice(Address _a) { return get<2>(addresses[_a]); }
void suicide(Address _a) bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out)
{ {
for (auto const& i: get<3>(addresses[myAddress])) Transaction t;
if (i.second) t.value = _value;
get<0>(addresses[_a]) += fees.m_memoryFee; t.gasPrice = gasPrice;
get<0>(addresses[_a]) += get<0>(addresses[myAddress]); t.gas = *_gas;
addresses.erase(myAddress); t.data = _data.toVector();
t.receiveAddress = _receiveAddress;
txs.push_back(t);
(void)_out;
return true;
} }
void setTransaction(Address _txSender, u256 _txValue, u256s const& _txData) void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data)
{ {
txSender = _txSender; caller = origin = _caller;
txValue = _txValue; value = _value;
txData = _txData; data = &_data;
gasPrice = _gasPrice;
} }
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData) void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, bytes const& _code, map<u256, u256> const& _storage)
{ {
myAddress = _myAddress; myAddress = _myAddress;
set(myAddress, _myBalance, _myNonce, _myData); set(myAddress, _myBalance, _myNonce, _code, _storage);
} }
void set(Address _a, u256 _myBalance, u256 _myNonce, u256s _myData) void set(Address _a, u256 _myBalance, u256 _myNonce, bytes const& _code, map<u256, u256> const& _storage)
{ {
get<0>(addresses[_a]) = _myBalance; get<0>(addresses[_a]) = _myBalance;
get<1>(addresses[_a]) = _myNonce; get<1>(addresses[_a]) = _myNonce;
get<2>(addresses[_a]) = 0; get<2>(addresses[_a]) = 0;
for (unsigned i = 0; i < _myData.size(); ++i) get<3>(addresses[_a]) = _storage;
#ifdef __clang__ get<4>(addresses[_a]) = _code;
{ }
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a];
map<u256, u256> & third = get<3>(address); void reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _storage)
auto sFinder = third.find(i); {
if (sFinder != third.end()) txs.clear();
sFinder->second = _myData[i]; addresses.clear();
else set(myAddress, _myBalance, _myNonce, get<4>(addresses[myAddress]), _storage);
third.insert(std::make_pair(i, _myData[i]));
}
#else
get<3>(addresses[_a])[i] = _myData[i];
#endif
} }
mObject exportEnv() mObject exportEnv()
@ -148,7 +130,6 @@ public:
push(ret, "currentDifficulty", currentBlock.difficulty); push(ret, "currentDifficulty", currentBlock.difficulty);
push(ret, "currentTimestamp", currentBlock.timestamp); push(ret, "currentTimestamp", currentBlock.timestamp);
ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress);
push(ret, "feeMultiplier", fees.multiplier());
return ret; return ret;
} }
@ -159,7 +140,6 @@ public:
currentBlock.difficulty = toInt(_o["currentDifficulty"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]);
currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.timestamp = toInt(_o["currentTimestamp"]);
currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
fees.setMultiplier(toInt(_o["feeMultiplier"]));
} }
static u256 toInt(mValue const& _v) static u256 toInt(mValue const& _v)
@ -175,6 +155,19 @@ public:
return 0; return 0;
} }
static byte toByte(mValue const& _v)
{
switch (_v.type())
{
case str_type: return (byte)stoi(_v.get_str());
case int_type: return (byte)_v.get_uint64();
case bool_type: return (byte)_v.get_bool();
case real_type: return (byte)_v.get_real();
default: cwarn << "Bad type for scalar: " << _v.type();
}
return 0;
}
static void push(mObject& o, string const& _n, u256 _v) static void push(mObject& o, string const& _n, u256 _v)
{ {
if (_v < (u256)1 << 64) if (_v < (u256)1 << 64)
@ -199,7 +192,6 @@ public:
mObject o; mObject o;
push(o, "balance", get<0>(a.second)); push(o, "balance", get<0>(a.second));
push(o, "nonce", get<1>(a.second)); push(o, "nonce", get<1>(a.second));
push(o, "extroPrice", get<2>(a.second));
mObject store; mObject store;
string curKey; string curKey;
@ -239,42 +231,18 @@ public:
auto& a = addresses[Address(i.first)]; auto& a = addresses[Address(i.first)];
get<0>(a) = toInt(o["balance"]); get<0>(a) = toInt(o["balance"]);
get<1>(a) = toInt(o["nonce"]); get<1>(a) = toInt(o["nonce"]);
get<2>(a) = toInt(o["extroPrice"]);
if (o.count("store")) if (o.count("store"))
for (auto const& j: o["store"].get_obj()) for (auto const& j: o["store"].get_obj())
{ {
u256 adr(j.first); u256 adr(j.first);
for (auto const& k: j.second.get_array()) for (auto const& k: j.second.get_array())
#ifdef __clang__
{
map<u256, u256> & third = get<3>(a);
auto sFinder = third.find(adr);
if (sFinder != third.end())
sFinder->second = toInt(k);
else
third.insert(std::make_pair(adr, toInt(k)));
adr++;
}
#else
get<3>(a)[adr++] = toInt(k); get<3>(a)[adr++] = toInt(k);
#endif
} }
if (o.count("code")) if (o.count("code"))
{ {
u256s d = compileLisp(o["code"].get_str()); bytes e;
for (unsigned i = 0; i < d.size(); ++i) bytes d = compileLisp(o["code"].get_str(), false, e);
#ifdef __clang__ get<4>(a) = d;
{
map<u256, u256> & third = get<3>(a);
auto sFinder = third.find(i);
if (sFinder != third.end())
sFinder->second = d[i];
else
third.insert(std::make_pair(i, d[i]));
}
#else
get<3>(a)[(u256)i] = d[i];
#endif
} }
} }
} }
@ -283,10 +251,12 @@ public:
{ {
mObject ret; mObject ret;
ret["address"] = toString(myAddress); ret["address"] = toString(myAddress);
ret["sender"] = toString(txSender); ret["caller"] = toString(caller);
push(ret, "value", txValue); ret["origin"] = toString(origin);
push(ret, "value", value);
push(ret, "gasPrice", gasPrice);
mArray d; mArray d;
for (auto const& i: txData) for (auto const& i: data)
push(d, i); push(d, i);
ret["data"] = d; ret["data"] = d;
return ret; return ret;
@ -295,10 +265,14 @@ public:
void importExec(mObject& _o) void importExec(mObject& _o)
{ {
myAddress = Address(_o["address"].get_str()); myAddress = Address(_o["address"].get_str());
txSender = Address(_o["sender"].get_str()); caller = Address(_o["caller"].get_str());
txValue = toInt(_o["value"]); origin = Address(_o["origin"].get_str());
value = toInt(_o["value"]);
gasPrice = toInt(_o["gasPrice"]);
thisTxData.clear();
for (auto const& j: _o["data"].get_array()) for (auto const& j: _o["data"].get_array())
txData.push_back(toInt(j)); thisTxData.push_back(toByte(j));
data = &thisTxData;
} }
mArray exportTxs() mArray exportTxs()
@ -327,20 +301,14 @@ public:
t.receiveAddress = Address(tx["destination"].get_str()); t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]); t.value = toInt(tx["value"]);
for (auto const& j: tx["data"].get_array()) for (auto const& j: tx["data"].get_array())
t.data.push_back(toInt(j)); t.data.push_back(toByte(j));
txs.push_back(t); txs.push_back(t);
} }
} }
void reset(u256 _myBalance, u256 _myNonce, u256s _myData) map<Address, tuple<u256, u256, u256, map<u256, u256>, bytes>> addresses;
{
txs.clear();
addresses.clear();
set(myAddress, _myBalance, _myNonce, _myData);
}
map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
Transactions txs; Transactions txs;
bytes thisTxData;
}; };
#define CREATE_TESTS 0 #define CREATE_TESTS 0
@ -380,21 +348,37 @@ public:
if (_fillin) if (_fillin)
o["pre"] = mValue(fev.exportState()); o["pre"] = mValue(fev.exportState());
bytes output;
for (auto i: o["exec"].get_array()) for (auto i: o["exec"].get_array())
{ {
fev.importExec(i.get_obj()); fev.importExec(i.get_obj());
vm.go(fev); output = vm.go(fev).toBytes();
} }
if (_fillin) if (_fillin)
{ {
o["post"] = mValue(fev.exportState()); o["post"] = mValue(fev.exportState());
o["txs"] = fev.exportTxs(); o["txs"] = fev.exportTxs();
mArray df;
for (auto const& i: output)
FakeExtVM::push(df, i);
o["out"] = df;
} }
else else
{ {
FakeExtVM test; FakeExtVM test;
test.importState(o["post"].get_obj()); test.importState(o["post"].get_obj());
test.importTxs(o["txs"].get_array()); test.importTxs(o["txs"].get_array());
int i = 0;
for (auto const& d: o["out"].get_array())
{
if (output[i] != FakeExtVM::toInt(d))
{
cwarn << "Test failed: output byte" << i << "different.";
passed = false;
}
++i;
}
if (test.addresses != fev.addresses) if (test.addresses != fev.addresses)
{ {
cwarn << "Test failed: state different."; cwarn << "Test failed: state different.";
@ -424,13 +408,12 @@ public:
cb.difficulty = 256; cb.difficulty = 256;
cb.timestamp = 1; cb.timestamp = 1;
cb.coinbaseAddress = toAddress(sha3("coinbase")); cb.coinbaseAddress = toAddress(sha3("coinbase"));
FeeStructure fees; FakeExtVM fev(pb, cb, 0);
fees.setMultiplier(1); bytes init;
FakeExtVM fev(fees, pb, cb, 0); fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))", false, init), map<u256, u256>());
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
o["env"] = fev.exportEnv(); o["env"] = fev.exportEnv();
o["pre"] = fev.exportState(); o["pre"] = fev.exportState();
fev.setTransaction(toAddress(sha3("sender")), ether, u256s()); fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes());
mArray execs; mArray execs;
execs.push_back(fev.exportExec()); execs.push_back(fev.exportExec());
o["exec"] = execs; o["exec"] = execs;

115
walleth/CMakeLists.txt

@ -0,0 +1,115 @@
cmake_policy(SET CMP0015 NEW)
if ("${TARGET_PLATFORM}" STREQUAL "w64")
cmake_policy(SET CMP0020 NEW)
endif ()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(..)
link_directories(../libethereum)
# Find Qt5 for Apple and update src_list for windows
if (APPLE)
# homebrew defaults to qt4 and installs qt5 as 'keg-only'
# which places it into /usr/local/opt insteadof /usr/local.
set(CMAKE_PREFIX_PATH /usr/local/opt/qt5)
include_directories(/usr/local/opt/qt5/include /usr/local/include)
elseif (${TARGET_PLATFORM} STREQUAL "w64")
set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp)
elseif (UNIX)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake")
endif ()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Qml REQUIRED)
find_package(Qt5Network REQUIRED)
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_add_resources(RESOURCE_ADDED Resources.qrc)
# Set name of binary and add_executable()
if (APPLE)
set(EXECUTEABLE Walleth)
set(CMAKE_INSTALL_PREFIX ./)
set(BIN_INSTALL_DIR ".")
set(DOC_INSTALL_DIR ".")
set(PROJECT_VERSION "${ETH_VERSION}")
set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_NAME} ${PROJECT_VERSION}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT_YEAR} ${PROJECT_VENDOR}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_DOMAIN_SECOND}.${PROJECT_DOMAIN_FIRST}")
set(MACOSX_BUNDLE_BUNDLE_NAME ${EXECUTEABLE})
include(BundleUtilities)
add_executable(${EXECUTEABLE} MACOSX_BUNDLE Main.ui ${RESOURCE_ADDED} ${SRC_LIST})
else ()
set(EXECUTEABLE walleth)
add_executable(${EXECUTEABLE} Main.ui ${RESOURCE_ADDED} ${SRC_LIST})
endif ()
qt5_use_modules(${EXECUTEABLE} Core Gui Widgets Network Quick Qml)
target_link_libraries(${EXECUTEABLE} ethereum secp256k1 ${CRYPTOPP_LIBRARIES})
if (APPLE)
if (${ADDFRAMEWORKS})
set_target_properties(${EXECUTEABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in")
endif ()
SET_SOURCE_FILES_PROPERTIES(${EXECUTEABLE} PROPERTIES MACOSX_PACKAGE_LOCATION MacOS)
# This is a workaround for when the build-type defaults to Debug, and when a multi-config generator like xcode is used, where the type
# will not be set but defaults to release.
set(generator_lowercase "${CMAKE_GENERATOR}")
string(TOLOWER "${CMAKE_GENERATOR}" generator_lowercase)
if (generator_lowercase STREQUAL "xcode")
# TODO: Not sure how to resolve this. Possibly \${TARGET_BUILD_DIR}
set(binary_build_dir "${CMAKE_CURRENT_BINARY_DIR}/Debug")
else ()
set(binary_build_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif ()
set(APPS ${binary_build_dir}/${EXECUTEABLE}.app)
# This tool and the next will automatically looked at the linked libraries in order to determine what dependencies are required. Thus, target_link_libaries only needs to add ethereum and secp256k1 (above)
install(CODE "
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS 1)
fixup_bundle(\"${APPS}\" \"${BUNDLELIBS}\" \"../libethereum ../secp256k1\")
" COMPONENT RUNTIME )
if (${ADDFRAMEWORKS})
add_custom_target(addframeworks ALL
COMMAND /usr/local/opt/qt5/bin/macdeployqt ${binary_build_dir}/${EXECUTEABLE}.app
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
DEPENDS ${PROJECT_NAME}
)
endif ()
elseif (${TARGET_PLATFORM} STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-keep-inline-dllexport -static-libgcc -static-libstdc++ -static")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-s -Wl,-subsystem,windows -mthreads -L/usr/x86_64-w64-mingw32/plugins/platforms")
target_link_libraries(${EXECUTEABLE} gcc)
target_link_libraries(${EXECUTEABLE} mingw32 qtmain mswsock iphlpapi qwindows shlwapi Qt5PlatformSupport gdi32 comdlg32 oleaut32 imm32 winmm ole32 uuid ws2_32)
target_link_libraries(${EXECUTEABLE} boost_system-mt-s)
target_link_libraries(${EXECUTEABLE} boost_filesystem-mt-s)
target_link_libraries(${EXECUTEABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTEABLE} Qt5PlatformSupport)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else ()
target_link_libraries(${EXECUTEABLE} boost_system)
target_link_libraries(${EXECUTEABLE} boost_filesystem)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTEABLE} ${CMAKE_THREAD_LIBS_INIT})
install( TARGETS ${EXECUTEABLE} RUNTIME DESTINATION bin )
endif ()

168
walleth/Main.ui

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Main</class>
<widget class="QMainWindow" name="Main">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>562</width>
<height>488</height>
</rect>
</property>
<property name="windowTitle">
<string>Walleth</string>
</property>
<property name="dockNestingEnabled">
<bool>true</bool>
</property>
<property name="dockOptions">
<set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::VerticalTabs</set>
</property>
<property name="sizeGripEnabled" stdset="0">
<bool>true</bool>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="fullDisplay">
<item>
<widget class="QLabel" name="balance">
<property name="text">
<string>0 wei</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="peerCount">
<property name="text">
<string>0 peers</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="blockCount">
<property name="text">
<string>1 block</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>562</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="quit"/>
</widget>
<widget class="QMenu" name="menu_Network">
<property name="title">
<string>&amp;Network</string>
</property>
<addaction name="upnp"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
<widget class="QMenu" name="menu_Tools">
<property name="title">
<string>T&amp;ools</string>
</property>
<addaction name="mine"/>
<addaction name="create"/>
<addaction name="preview"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="about"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Network"/>
<addaction name="menu_Tools"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
<action name="upnp">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Use &amp;UPnP</string>
</property>
</action>
<action name="connect">
<property name="text">
<string>&amp;Connect to Peer...</string>
</property>
</action>
<action name="net">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable &amp;Network</string>
</property>
</action>
<action name="mine">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Mine</string>
</property>
</action>
<action name="create">
<property name="text">
<string>&amp;New Address</string>
</property>
</action>
<action name="about">
<property name="text">
<string>&amp;About...</string>
</property>
</action>
<action name="preview">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Preview</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

448
walleth/MainWin.cpp

@ -0,0 +1,448 @@
#include <QtNetwork/QNetworkReply>
#include <QtQuick/QQuickView>
//#include <QtQml/QQmlContext>
//#include <QtQml/QQmlEngine>
#include <QtQml/QtQml>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtGui/QClipboard>
#include <QtCore/QtCore>
#include <libethereum/Dagger.h>
#include <libethereum/Client.h>
#include <libethereum/Instruction.h>
#include <libethereum/FileSystem.h>
#include <libethereum/PeerServer.h>
#include "BuildInfo.h"
#include "MainWin.h"
#include "ui_Main.h"
using namespace std;
// types
using eth::bytes;
using eth::bytesConstRef;
using eth::h160;
using eth::h256;
using eth::u160;
using eth::u256;
using eth::u256s;
using eth::Address;
using eth::BlockInfo;
using eth::Client;
using eth::Instruction;
using eth::KeyPair;
using eth::NodeMode;
using eth::PeerInfo;
using eth::RLP;
using eth::Secret;
using eth::Transaction;
// functions
using eth::toHex;
using eth::assemble;
using eth::compileLisp;
using eth::disassemble;
using eth::formatBalance;
using eth::fromHex;
using eth::right160;
using eth::simpleDebugOut;
using eth::toLog2;
using eth::toString;
using eth::units;
// vars
using eth::g_logPost;
using eth::g_logVerbosity;
using eth::c_instructionInfo;
// Horrible global for the mainwindow. Needed for the QEthereums to find the Main window which acts as multiplexer for now.
// Can get rid of this once we've sorted out ITC for signalling & multiplexed querying.
Main* g_main = nullptr;
QEthereum::QEthereum(QObject* _p): QObject(_p)
{
connect(g_main, SIGNAL(changed()), SIGNAL(changed()));
}
QEthereum::~QEthereum()
{
}
Client* QEthereum::client() const
{
return g_main->client();
}
Address QEthereum::coinbase() const
{
return client()->address();
}
void QEthereum::setCoinbase(Address _a)
{
if (client()->address() != _a)
{
client()->setAddress(_a);
changed();
}
}
QAccount::QAccount(QObject*)
{
}
QAccount::~QAccount()
{
}
void QAccount::setEthereum(QEthereum* _eth)
{
if (m_eth == _eth)
return;
if (m_eth)
disconnect(m_eth, SIGNAL(changed()), this, SIGNAL(changed()));
m_eth = _eth;
if (m_eth)
connect(m_eth, SIGNAL(changed()), this, SIGNAL(changed()));
ethChanged();
changed();
}
u256 QAccount::balance() const
{
if (m_eth)
return m_eth->balanceAt(m_address);
return 0;
}
double QAccount::txCount() const
{
if (m_eth)
return m_eth->txCountAt(m_address);
return 0;
}
bool QAccount::isContract() const
{
if (m_eth)
return m_eth->isContractAt(m_address);
return 0;
}
u256 QEthereum::balanceAt(Address _a) const
{
return client()->postState().balance(_a);
}
bool QEthereum::isContractAt(Address _a) const
{
return client()->postState().isContractAddress(_a);
}
bool QEthereum::isMining() const
{
return client()->isMining();
}
bool QEthereum::isListening() const
{
return client()->haveNetwork();
}
void QEthereum::setMining(bool _l)
{
if (_l)
client()->startMining();
else
client()->stopMining();
}
void QEthereum::setListening(bool _l)
{
if (_l)
client()->startNetwork();
else
client()->stopNetwork();
}
double QEthereum::txCountAt(Address _a) const
{
return (double)client()->postState().transactionsFrom(_a);
}
unsigned QEthereum::peerCount() const
{
return (unsigned)client()->peerCount();
}
void QEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _code, QByteArray _init)
{
client()->transact(_secret, _amount, bytes(_code.data(), _code.data() + _code.size()), bytes(_init.data(), _init.data() + _init.size()), _gas, _gasPrice);
}
void QEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _data)
{
client()->transact(_secret, _amount, _dest, bytes(_data.data(), _data.data() + _data.size()), _gas, _gasPrice);
}
Main::Main(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main)
{
setWindowFlags(Qt::Window);
ui->setupUi(this);
setWindowIcon(QIcon(":/Ethereum.png"));
g_main = this;
m_client.reset(new Client("Walleth", Address(), eth::getDataDir() + "/Walleth"));
qRegisterMetaType<eth::u256>("eth::u256");
qRegisterMetaType<eth::KeyPair>("eth::KeyPair");
qRegisterMetaType<eth::Secret>("eth::Secret");
qRegisterMetaType<eth::Address>("eth::Address");
qRegisterMetaType<QAccount*>("QAccount*");
qRegisterMetaType<QEthereum*>("QEthereum*");
qmlRegisterType<QEthereum>("org.ethereum", 1, 0, "Ethereum");
qmlRegisterType<QAccount>("org.ethereum", 1, 0, "Account");
qmlRegisterSingletonType<U256Helper>("org.ethereum", 1, 0, "Balance", QEthereum::constructU256Helper);
qmlRegisterSingletonType<KeyHelper>("org.ethereum", 1, 0, "Key", QEthereum::constructKeyHelper);
/*
ui->librariesView->setModel(m_libraryMan);
ui->graphsView->setModel(m_graphMan);
*/
m_view = new QQuickView();
// QQmlContext* context = m_view->rootContext();
// context->setContextProperty("u256", new U256Helper(this));
m_view->setSource(QUrl("qrc:/Simple.qml"));
QWidget* w = QWidget::createWindowContainer(m_view);
m_view->setResizeMode(QQuickView::SizeRootObjectToView);
ui->fullDisplay->insertWidget(0, w);
m_view->create();
// m_timelinesItem = m_view->rootObject()->findChild<TimelinesItem*>("timelines");
readSettings();
refresh();
m_refreshNetwork = new QTimer(this);
connect(m_refreshNetwork, SIGNAL(timeout()), SLOT(refreshNetwork()));
m_refreshNetwork->start(1000);
connect(this, SIGNAL(changed()), SLOT(refresh()));
connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r)
{
m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts);
if (m_servers.size())
{
ui->net->setChecked(true);
on_net_triggered(true);
}
});
QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc" + QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1) + ".txt"));
r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36");
m_webCtrl.get(r);
srand(time(0));
startTimer(200);
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->blockCount);
}
Main::~Main()
{
writeSettings();
}
void Main::timerEvent(QTimerEvent *)
{
if (m_client->changed())
changed();
}
void Main::on_about_triggered()
{
QMessageBox::about(this, "About Walleth PoC-" + QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1), "Walleth/v" ETH_QUOTED(ETH_VERSION) "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM) " - " ETH_QUOTED(ETH_COMMIT_HASH) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Tim Hughes, Eric Lombrozo, Marko Simovic, Alex Leverington and several others.");
}
void Main::writeSettings()
{
QSettings s("ethereum", "walleth");
QByteArray b;
b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("address", b);
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("clientName", m_clientName);
s.setValue("idealPeers", m_idealPeers);
s.setValue("port", m_port);
if (client()->peerServer())
{
bytes d = client()->peerServer()->savePeers();
m_peers = QByteArray((char*)d.data(), (int)d.size());
}
s.setValue("peers", m_peers);
s.setValue("geometry", saveGeometry());
s.setValue("windowState", saveState());
}
void Main::readSettings()
{
QSettings s("ethereum", "walleth");
restoreGeometry(s.value("geometry").toByteArray());
restoreState(s.value("windowState").toByteArray());
QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
m_myKeys.append(KeyPair(k));
}
}
//m_eth->setAddress(m_myKeys.last().address());
m_peers = s.value("peers").toByteArray();
ui->upnp->setChecked(s.value("upnp", true).toBool());
m_clientName = s.value("clientName", "").toString();
m_idealPeers = s.value("idealPeers", 5).toInt();
m_port = s.value("port", 30303).toInt();
}
void Main::refreshNetwork()
{
auto ps = client()->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
}
eth::State const& Main::state() const
{
return ui->preview->isChecked() ? client()->postState() : client()->state();
}
void Main::refresh()
{
eth::ClientGuard l(client());
auto const& st = state();
auto d = client()->blockChain().details();
auto diff = BlockInfo(client()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("#%1 @%3 T%2").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)));
m_keysChanged = false;
u256 totalBalance = 0;
for (auto i: m_myKeys)
{
u256 b = st.balance(i.address());
totalBalance += b;
}
ui->balance->setText(QString::fromStdString(formatBalance(totalBalance)));
}
void Main::on_net_triggered(bool _auto)
{
string n = "Walleth/v" ETH_QUOTED(ETH_VERSION);
if (m_clientName.size())
n += "/" + m_clientName.toStdString();
n += "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM);
client()->setClientVersion(n);
if (ui->net->isChecked())
{
if (_auto)
{
QString s = m_servers[rand() % m_servers.size()];
client()->startNetwork(m_port, s.section(':', 0, 0).toStdString(), s.section(':', 1).toInt(), NodeMode::Full, m_idealPeers, std::string(), ui->upnp->isChecked());
}
else
client()->startNetwork(m_port, string(), 0, NodeMode::Full, m_idealPeers, std::string(), ui->upnp->isChecked());
if (m_peers.size())
client()->peerServer()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
}
else
client()->stopNetwork();
}
void Main::on_connect_triggered()
{
if (!ui->net->isChecked())
{
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(":"))
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
client()->connect(host, port);
}
}
void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
client()->setAddress(m_myKeys.last().address());
client()->startMining();
}
else
client()->stopMining();
}
void Main::on_create_triggered()
{
m_myKeys.append(KeyPair::create());
m_keysChanged = true;
}
// extra bits needed to link on VS
#ifdef _MSC_VER
// include moc file, ofuscated to hide from automoc
#include\
"moc_MainWin.cpp"
// specify library dependencies, it's easier to do here than in the project since we can control the "d" debug suffix
#ifdef _DEBUG
#define QTLIB(x) x"d.lib"
#else
#define QTLIB(x) x".lib"
#endif
#pragma comment(lib, QTLIB("Qt5PlatformSupport"))
#pragma comment(lib, QTLIB("Qt5Core"))
#pragma comment(lib, QTLIB("Qt5GUI"))
#pragma comment(lib, QTLIB("Qt5Widgets"))
#pragma comment(lib, QTLIB("Qt5Network"))
#pragma comment(lib, QTLIB("Qt5Quick"))
#pragma comment(lib, QTLIB("Qt5Declarative"))
#pragma comment(lib, QTLIB("Qt5Qml"))
#pragma comment(lib, QTLIB("qwindows"))
#pragma comment(lib, "Imm32.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "winmm.lib")
#endif

224
walleth/MainWin.h

@ -0,0 +1,224 @@
#ifndef MAIN_H
#define MAIN_H
#include <QtNetwork/QNetworkAccessManager>
#include <QtCore/QAbstractListModel>
#include <QtCore/QMutex>
#include <QtWidgets/QMainWindow>
#include <libethereum/CommonEth.h>
namespace Ui {
class Main;
}
namespace eth {
class Client;
class State;
}
class QQuickView;
class QQmlEngine;
class QJSEngine;
class QEthereum;
class QAccount;
Q_DECLARE_METATYPE(eth::u256)
Q_DECLARE_METATYPE(eth::Address)
Q_DECLARE_METATYPE(eth::Secret)
Q_DECLARE_METATYPE(eth::KeyPair)
Q_DECLARE_METATYPE(QEthereum*)
Q_DECLARE_METATYPE(QAccount*)
class U256Helper: public QObject
{
Q_OBJECT
public:
U256Helper(QObject* _p = nullptr): QObject(_p) {}
Q_INVOKABLE eth::u256 add(eth::u256 _a, eth::u256 _b) const { return _a + _b; }
Q_INVOKABLE eth::u256 sub(eth::u256 _a, eth::u256 _b) const { return _a - _b; }
Q_INVOKABLE eth::u256 mul(eth::u256 _a, int _b) const { return _a * _b; }
Q_INVOKABLE eth::u256 mul(int _a, eth::u256 _b) const { return _a * _b; }
Q_INVOKABLE eth::u256 div(eth::u256 _a, int _b) const { return _a / _b; }
Q_INVOKABLE eth::u256 wei(double _s) const { return (eth::u256)_s; }
Q_INVOKABLE eth::u256 szabo(double _s) const { return (eth::u256)(_s * (double)eth::szabo); }
Q_INVOKABLE eth::u256 finney(double _s) const { return (eth::u256)(_s * (double)eth::finney); }
Q_INVOKABLE eth::u256 ether(double _s) const { return (eth::u256)(_s * (double)eth::ether); }
Q_INVOKABLE eth::u256 wei(unsigned _s) const { return (eth::u256)_s; }
Q_INVOKABLE eth::u256 szabo(unsigned _s) const { return (eth::u256)(_s * eth::szabo); }
Q_INVOKABLE eth::u256 finney(unsigned _s) const { return (eth::u256)(_s * eth::finney); }
Q_INVOKABLE eth::u256 ether(unsigned _s) const { return (eth::u256)(_s * eth::ether); }
Q_INVOKABLE double toWei(eth::u256 _t) const { return (double)_t; }
Q_INVOKABLE double toSzabo(eth::u256 _t) const { return toWei(_t) / (double)eth::szabo; }
Q_INVOKABLE double toFinney(eth::u256 _t) const { return toWei(_t) / (double)eth::finney; }
Q_INVOKABLE double toEther(eth::u256 _t) const { return toWei(_t) / (double)eth::ether; }
Q_INVOKABLE double value(eth::u256 _t) const { return (double)_t; }
Q_INVOKABLE QString stringOf(eth::u256 _t) const { return QString::fromStdString(eth::formatBalance(_t)); }
};
class KeyHelper: public QObject
{
Q_OBJECT
public:
KeyHelper(QObject* _p = nullptr): QObject(_p) {}
Q_INVOKABLE eth::KeyPair create() const { return eth::KeyPair::create(); }
Q_INVOKABLE eth::Address address(eth::KeyPair _p) const { return _p.address(); }
Q_INVOKABLE eth::Secret secret(eth::KeyPair _p) const { return _p.secret(); }
Q_INVOKABLE eth::KeyPair keypair(eth::Secret _k) const { return eth::KeyPair(_k); }
Q_INVOKABLE bool isNull(eth::Address _a) const { return !_a; }
Q_INVOKABLE eth::Address addressOf(QString _s) const { return eth::Address(_s.toStdString()); }
Q_INVOKABLE QString stringOf(eth::Address _a) const { return QString::fromStdString(eth::toHex(_a.asArray())); }
Q_INVOKABLE QString toAbridged(eth::Address _a) const { return QString::fromStdString(_a.abridged()); }
};
class QAccount: public QObject
{
Q_OBJECT
public:
QAccount(QObject* _p = nullptr);
virtual ~QAccount();
Q_INVOKABLE QEthereum* ethereum() const { return m_eth; }
Q_INVOKABLE eth::u256 balance() const;
Q_INVOKABLE double txCount() const;
Q_INVOKABLE bool isContract() const;
// TODO: past transactions models.
public slots:
void setEthereum(QEthereum* _eth);
signals:
void changed();
void ethChanged();
private:
QEthereum* m_eth = nullptr;
eth::Address m_address;
Q_PROPERTY(eth::u256 balance READ balance NOTIFY changed STORED false)
Q_PROPERTY(double txCount READ txCount NOTIFY changed STORED false)
Q_PROPERTY(bool isContract READ isContract NOTIFY changed STORED false)
Q_PROPERTY(eth::Address address MEMBER m_address NOTIFY changed)
Q_PROPERTY(QEthereum* ethereum READ ethereum WRITE setEthereum NOTIFY ethChanged)
};
class QEthereum: public QObject
{
Q_OBJECT
public:
QEthereum(QObject* _p = nullptr);
virtual ~QEthereum();
eth::Client* client() const;
static QObject* constructU256Helper(QQmlEngine*, QJSEngine*) { return new U256Helper; }
static QObject* constructKeyHelper(QQmlEngine*, QJSEngine*) { return new KeyHelper; }
Q_INVOKABLE eth::Address coinbase() const;
Q_INVOKABLE bool isListening() const;
Q_INVOKABLE bool isMining() const;
Q_INVOKABLE eth::u256 balanceAt(eth::Address _a) const;
Q_INVOKABLE double txCountAt(eth::Address _a) const;
Q_INVOKABLE bool isContractAt(eth::Address _a) const;
Q_INVOKABLE unsigned peerCount() const;
Q_INVOKABLE QEthereum* self() { return this; }
public slots:
void transact(eth::Secret _secret, eth::Address _dest, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _data);
void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _code, QByteArray _init);
void setCoinbase(eth::Address);
void setMining(bool _l);
void setListening(bool _l);
signals:
void changed();
// void netChanged();
// void miningChanged();
private:
Q_PROPERTY(eth::Address coinbase READ coinbase WRITE setCoinbase NOTIFY changed)
Q_PROPERTY(bool listening READ isListening WRITE setListening)
Q_PROPERTY(bool mining READ isMining WRITE setMining)
};
class Main : public QMainWindow
{
Q_OBJECT
public:
explicit Main(QWidget *parent = 0);
~Main();
eth::Client* client() const { return m_client.get(); }
private slots:
void on_connect_triggered();
void on_mine_triggered();
void on_create_triggered();
void on_net_triggered(bool _auto = false);
void on_about_triggered();
void on_preview_triggered() { refresh(); }
void on_quit_triggered() { close(); }
void refresh();
void refreshNetwork();
signals:
void changed();
protected:
virtual void timerEvent(QTimerEvent *);
private:
/* QString pretty(eth::Address _a) const;
QString render(eth::Address _a) const;
eth::Address fromString(QString const& _a) const;
*/
eth::State const& state() const;
void updateFee();
void readSettings();
void writeSettings();
eth::u256 fee() const;
eth::u256 total() const;
eth::u256 value() const;
std::unique_ptr<Ui::Main> ui;
QByteArray m_peers;
QMutex m_guiLock;
QTimer* m_refresh;
QTimer* m_refreshNetwork;
QVector<eth::KeyPair> m_myKeys;
bool m_keysChanged = false;
int m_port;
int m_idealPeers;
QString m_clientName;
QStringList m_servers;
QQuickView* m_view;
QNetworkAccessManager m_webCtrl;
std::unique_ptr<eth::Client> m_client;
};
#endif // MAIN_H

5
walleth/Resources.qrc

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>Simple.qml</file>
</qresource>
</RCC>

38
walleth/Simple.qml

@ -0,0 +1,38 @@
import QtQml 2.2
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
import Qt.labs.settings 1.0
import org.ethereum 1.0
Item {
id: main
anchors.fill: parent
anchors.margins: 9
// Qt.application.name: "Walleth"
// Qt.application.organization: "Ethereum"
// Qt.application.domain: "org.ethereum"
Ethereum {
id: eth
}
Account {
id: myAccount
address: Key.addressOf("84fc4ba9373c30bfe32d8c5a502854e7f1175878")
ethereum: eth
// TODO: state: eth.latest // could be eth.pending
// will provide balance, txCount, isContract, incomingTransactions (list model), outgoingTransactions (list model).
// transaction lists' items will provide value, from, to, final balance.
}
// KeyPair provides makeTransaction(recvAddress, value, data (array))
Text {
text: "Balance: " + Balance.stringOf(myAccount.balance) + " [" + myAccount.txCount + "]" + "\nAccount: " + Key.stringOf(myAccount.address)
Layout.minimumHeight: 30
Layout.fillHeight: true
Layout.fillWidth: true
}
}

11
walleth/main.cpp

@ -0,0 +1,11 @@
#include "MainWin.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Main w;
w.show();
return a.exec();
}

12
windows/Ethereum.sln

@ -23,7 +23,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCryptoPP", "LibCryptoPP.
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibMiniUPnPc", "LibMiniUPnPc.vcxproj", "{1B1CA20E-39C3-4D9B-AC37-3783048E6672}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibMiniUPnPc", "LibMiniUPnPc.vcxproj", "{1B1CA20E-39C3-4D9B-AC37-3783048E6672}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Alethzero", "Alethzero.vcxproj", "{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AlethZero", "Alethzero.vcxproj", "{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Walleth", "Walleth.vcxproj", "{326EF470-463F-4751-A22A-48BBAAD8B143}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -105,6 +107,14 @@ Global
{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Win32.Build.0 = Release|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Win32.Build.0 = Release|Win32
{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.ActiveCfg = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.ActiveCfg = Release|x64
{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.Build.0 = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.Build.0 = Release|x64
{326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|Win32.ActiveCfg = Debug|Win32
{326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|Win32.Build.0 = Debug|Win32
{326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|x64.ActiveCfg = Debug|x64
{326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|x64.Build.0 = Debug|x64
{326EF470-463F-4751-A22A-48BBAAD8B143}.Release|Win32.ActiveCfg = Release|Win32
{326EF470-463F-4751-A22A-48BBAAD8B143}.Release|Win32.Build.0 = Release|Win32
{326EF470-463F-4751-A22A-48BBAAD8B143}.Release|x64.ActiveCfg = Release|x64
{326EF470-463F-4751-A22A-48BBAAD8B143}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

8
windows/LibCryptoPP.vcxproj

@ -116,7 +116,7 @@
</PrecompiledHeader> </PrecompiledHeader>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -129,7 +129,7 @@
</PrecompiledHeader> </PrecompiledHeader>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -144,7 +144,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -161,7 +161,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4189;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>

2
windows/LibEthereum.props

@ -11,7 +11,7 @@
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<DisableSpecificWarnings>4068;4100;4127;4258;4505;4512;4706</DisableSpecificWarnings> <DisableSpecificWarnings>4068;4127;4258;4505;4512;4706;4714</DisableSpecificWarnings>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>

31
windows/LibEthereum.vcxproj

@ -28,21 +28,36 @@
<ClCompile Include="..\libethereum\BlockChain.cpp" /> <ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\BlockInfo.cpp" /> <ClCompile Include="..\libethereum\BlockInfo.cpp" />
<ClCompile Include="..\libethereum\Client.cpp" /> <ClCompile Include="..\libethereum\Client.cpp" />
<ClCompile Include="..\libethereum\Common.cpp" /> <ClCompile Include="..\libethereum\Common.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\libethereum\CommonData.cpp" />
<ClCompile Include="..\libethereum\CommonEth.cpp" />
<ClCompile Include="..\libethereum\CommonIO.cpp" />
<ClCompile Include="..\libethereum\Dagger.cpp" /> <ClCompile Include="..\libethereum\Dagger.cpp" />
<ClCompile Include="..\libethereum\Defaults.cpp" /> <ClCompile Include="..\libethereum\Defaults.cpp" />
<ClCompile Include="..\libethereum\FeeStructure.cpp" /> <ClCompile Include="..\libethereum\FeeStructure.cpp" />
<ClCompile Include="..\libethereum\FileSystem.cpp" /> <ClCompile Include="..\libethereum\FileSystem.cpp" />
<ClCompile Include="..\libethereum\FixedHash.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\libethereum\Instruction.cpp" /> <ClCompile Include="..\libethereum\Instruction.cpp" />
<ClCompile Include="..\libethereum\MemTrie.cpp" /> <ClCompile Include="..\libethereum\Log.cpp" />
<ClCompile Include="..\libethereum\PeerNetwork.cpp" /> <ClCompile Include="..\libethereum\PeerNetwork.cpp" />
<ClCompile Include="..\libethereum\PeerServer.cpp" />
<ClCompile Include="..\libethereum\PeerSession.cpp" />
<ClCompile Include="..\libethereum\RLP.cpp" /> <ClCompile Include="..\libethereum\RLP.cpp" />
<ClCompile Include="..\libethereum\State.cpp" /> <ClCompile Include="..\libethereum\State.cpp" />
<ClCompile Include="..\libethereum\Transaction.cpp" /> <ClCompile Include="..\libethereum\Transaction.cpp" />
<ClCompile Include="..\libethereum\TransactionQueue.cpp" /> <ClCompile Include="..\libethereum\TransactionQueue.cpp" />
<ClCompile Include="..\libethereum\TrieCommon.cpp" /> <ClCompile Include="..\libethereum\TrieCommon.cpp" />
<ClCompile Include="..\libethereum\TrieDB.cpp" /> <ClCompile Include="..\libethereum\TrieDB.cpp" />
<ClCompile Include="..\libethereum\TrieHash.cpp" />
<ClCompile Include="..\libethereum\UPnP.cpp" /> <ClCompile Include="..\libethereum\UPnP.cpp" />
<ClCompile Include="..\libethereum\VM.cpp" /> <ClCompile Include="..\libethereum\VM.cpp" />
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -59,22 +74,28 @@
<ClInclude Include="..\libethereum\BlockInfo.h" /> <ClInclude Include="..\libethereum\BlockInfo.h" />
<ClInclude Include="..\libethereum\Client.h" /> <ClInclude Include="..\libethereum\Client.h" />
<ClInclude Include="..\libethereum\Common.h" /> <ClInclude Include="..\libethereum\Common.h" />
<ClInclude Include="..\libethereum\CommonData.h" />
<ClInclude Include="..\libethereum\CommonEth.h" />
<ClInclude Include="..\libethereum\CommonIO.h" />
<ClInclude Include="..\libethereum\CryptoHeaders.h" />
<ClInclude Include="..\libethereum\Dagger.h" /> <ClInclude Include="..\libethereum\Dagger.h" />
<ClInclude Include="..\libethereum\Defaults.h" /> <ClInclude Include="..\libethereum\Defaults.h" />
<ClInclude Include="..\libethereum\Exceptions.h" /> <ClInclude Include="..\libethereum\Exceptions.h" />
<ClInclude Include="..\libethereum\ExtVMFace.h" /> <ClInclude Include="..\libethereum\ExtVMFace.h" />
<ClInclude Include="..\libethereum\FeeStructure.h" /> <ClInclude Include="..\libethereum\FeeStructure.h" />
<ClInclude Include="..\libethereum\FileSystem.h" /> <ClInclude Include="..\libethereum\FileSystem.h" />
<ClInclude Include="..\libethereum\FixedHash.h" />
<ClInclude Include="..\libethereum\Instruction.h" /> <ClInclude Include="..\libethereum\Instruction.h" />
<ClInclude Include="..\libethereum\MemTrie.h" /> <ClInclude Include="..\libethereum\Log.h" />
<ClInclude Include="..\libethereum\PeerNetwork.h" /> <ClInclude Include="..\libethereum\PeerNetwork.h" />
<ClInclude Include="..\libethereum\PeerServer.h" />
<ClInclude Include="..\libethereum\PeerSession.h" />
<ClInclude Include="..\libethereum\RLP.h" /> <ClInclude Include="..\libethereum\RLP.h" />
<ClInclude Include="..\libethereum\State.h" /> <ClInclude Include="..\libethereum\State.h" />
<ClInclude Include="..\libethereum\Transaction.h" /> <ClInclude Include="..\libethereum\Transaction.h" />
<ClInclude Include="..\libethereum\TransactionQueue.h" /> <ClInclude Include="..\libethereum\TransactionQueue.h" />
<ClInclude Include="..\libethereum\TrieCommon.h" /> <ClInclude Include="..\libethereum\TrieCommon.h" />
<ClInclude Include="..\libethereum\TrieDB.h" /> <ClInclude Include="..\libethereum\TrieDB.h" />
<ClInclude Include="..\libethereum\TrieHash.h" />
<ClInclude Include="..\libethereum\UPnP.h" /> <ClInclude Include="..\libethereum\UPnP.h" />
<ClInclude Include="..\libethereum\vector_ref.h" /> <ClInclude Include="..\libethereum\vector_ref.h" />
<ClInclude Include="..\libethereum\VM.h" /> <ClInclude Include="..\libethereum\VM.h" />

47
windows/LibEthereum.vcxproj.filters

@ -1,59 +1,70 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<ClCompile Include="..\libethereum\AddressState.cpp" />
<ClCompile Include="stdafx.cpp">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\BlockInfo.cpp" /> <ClCompile Include="..\libethereum\BlockInfo.cpp" />
<ClCompile Include="..\libethereum\Client.cpp" /> <ClCompile Include="..\libethereum\Client.cpp" />
<ClCompile Include="..\libethereum\Common.cpp" /> <ClCompile Include="..\libethereum\Common.cpp" />
<ClCompile Include="..\libethereum\CommonData.cpp" />
<ClCompile Include="..\libethereum\CommonEth.cpp" />
<ClCompile Include="..\libethereum\CommonIO.cpp" />
<ClCompile Include="..\libethereum\Dagger.cpp" /> <ClCompile Include="..\libethereum\Dagger.cpp" />
<ClCompile Include="..\libethereum\Defaults.cpp" /> <ClCompile Include="..\libethereum\Defaults.cpp" />
<ClCompile Include="..\libethereum\FeeStructure.cpp" />
<ClCompile Include="..\libethereum\FileSystem.cpp" /> <ClCompile Include="..\libethereum\FileSystem.cpp" />
<ClCompile Include="..\libethereum\MemTrie.cpp" /> <ClCompile Include="..\libethereum\FixedHash.cpp" />
<ClCompile Include="..\libethereum\Instruction.cpp" />
<ClCompile Include="..\libethereum\Log.cpp" />
<ClCompile Include="..\libethereum\PeerNetwork.cpp" /> <ClCompile Include="..\libethereum\PeerNetwork.cpp" />
<ClCompile Include="..\libethereum\PeerServer.cpp" />
<ClCompile Include="..\libethereum\PeerSession.cpp" />
<ClCompile Include="..\libethereum\RLP.cpp" /> <ClCompile Include="..\libethereum\RLP.cpp" />
<ClCompile Include="..\libethereum\State.cpp" /> <ClCompile Include="..\libethereum\State.cpp" />
<ClCompile Include="..\libethereum\Transaction.cpp" /> <ClCompile Include="..\libethereum\Transaction.cpp" />
<ClCompile Include="..\libethereum\TransactionQueue.cpp" /> <ClCompile Include="..\libethereum\TransactionQueue.cpp" />
<ClCompile Include="..\libethereum\TrieCommon.cpp" /> <ClCompile Include="..\libethereum\TrieCommon.cpp" />
<ClCompile Include="..\libethereum\TrieDB.cpp" /> <ClCompile Include="..\libethereum\TrieDB.cpp" />
<ClCompile Include="..\libethereum\TrieHash.cpp" />
<ClCompile Include="..\libethereum\UPnP.cpp" /> <ClCompile Include="..\libethereum\UPnP.cpp" />
<ClCompile Include="..\libethereum\AddressState.cpp" />
<ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\Instruction.cpp" />
<ClCompile Include="stdafx.cpp">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\FeeStructure.cpp" />
<ClCompile Include="..\libethereum\VM.cpp" /> <ClCompile Include="..\libethereum\VM.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Windows</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\BlockChain.h" />
<ClInclude Include="..\libethereum\BlockInfo.h" /> <ClInclude Include="..\libethereum\BlockInfo.h" />
<ClInclude Include="..\libethereum\Client.h" /> <ClInclude Include="..\libethereum\Client.h" />
<ClInclude Include="..\libethereum\Common.h" /> <ClInclude Include="..\libethereum\Common.h" />
<ClInclude Include="..\libethereum\CommonData.h" />
<ClInclude Include="..\libethereum\CommonEth.h" />
<ClInclude Include="..\libethereum\CommonIO.h" />
<ClInclude Include="..\libethereum\Dagger.h" /> <ClInclude Include="..\libethereum\Dagger.h" />
<ClInclude Include="..\libethereum\Defaults.h" /> <ClInclude Include="..\libethereum\Defaults.h" />
<ClInclude Include="..\libethereum\Exceptions.h" /> <ClInclude Include="..\libethereum\Exceptions.h" />
<ClInclude Include="..\libethereum\ExtVMFace.h" />
<ClInclude Include="..\libethereum\FeeStructure.h" />
<ClInclude Include="..\libethereum\FileSystem.h" /> <ClInclude Include="..\libethereum\FileSystem.h" />
<ClInclude Include="..\libethereum\FixedHash.h" />
<ClInclude Include="..\libethereum\Instruction.h" /> <ClInclude Include="..\libethereum\Instruction.h" />
<ClInclude Include="..\libethereum\MemTrie.h" /> <ClInclude Include="..\libethereum\Log.h" />
<ClInclude Include="..\libethereum\PeerNetwork.h" /> <ClInclude Include="..\libethereum\PeerNetwork.h" />
<ClInclude Include="..\libethereum\PeerServer.h" />
<ClInclude Include="..\libethereum\PeerSession.h" />
<ClInclude Include="..\libethereum\RLP.h" /> <ClInclude Include="..\libethereum\RLP.h" />
<ClInclude Include="..\libethereum\State.h" /> <ClInclude Include="..\libethereum\State.h" />
<ClInclude Include="..\libethereum\Transaction.h" /> <ClInclude Include="..\libethereum\Transaction.h" />
<ClInclude Include="..\libethereum\TransactionQueue.h" /> <ClInclude Include="..\libethereum\TransactionQueue.h" />
<ClInclude Include="..\libethereum\TrieCommon.h" /> <ClInclude Include="..\libethereum\TrieCommon.h" />
<ClInclude Include="..\libethereum\TrieDB.h" /> <ClInclude Include="..\libethereum\TrieDB.h" />
<ClInclude Include="..\libethereum\TrieHash.h" />
<ClInclude Include="..\libethereum\UPnP.h" /> <ClInclude Include="..\libethereum\UPnP.h" />
<ClInclude Include="..\libethereum\vector_ref.h" /> <ClInclude Include="..\libethereum\vector_ref.h" />
<ClInclude Include="..\libethereum\AddressState.h" />
<ClInclude Include="..\libethereum\BlockChain.h" />
<ClInclude Include="stdafx.h">
<Filter>Windows</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\ExtVMFace.h" />
<ClInclude Include="..\libethereum\FeeStructure.h" />
<ClInclude Include="..\libethereum\VM.h" /> <ClInclude Include="..\libethereum\VM.h" />
<ClInclude Include="..\libethereum\AddressState.h" />
<ClInclude Include="..\libethereum\CryptoHeaders.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Windows"> <Filter Include="Windows">

8
windows/LibLevelDB.vcxproj

@ -157,7 +157,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4018;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4018;4100;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -172,7 +172,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4018;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4018;4100;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -189,7 +189,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4018;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4018;4100;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -208,7 +208,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4018;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4018;4100;4244;4267;4389;4702;4722;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>

8
windows/LibMiniUPnPc.vcxproj

@ -109,7 +109,7 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -126,7 +126,7 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -145,7 +145,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -166,7 +166,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>

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

Loading…
Cancel
Save