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
*.suo
# Generated headers
*.h
*.user
*.user.*
*~

10
CMakeLists.txt

@ -17,6 +17,10 @@ if ("x${TARGET_PLATFORM}" STREQUAL "x")
set(TARGET_PLATFORM "linux")
endif ()
if ("${TARGET_PLATFORM}" STREQUAL "linux")
set(CMAKE_THREAD_LIBS_INIT pthread)
endif ()
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_SYSTEM_NAME Windows)
@ -58,7 +62,7 @@ else ()
endif ()
# 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_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG")
@ -150,8 +154,12 @@ add_subdirectory(test)
add_subdirectory(eth)
if (NOT HEADLESS)
add_subdirectory(alethzero)
add_subdirectory(walleth)
endif ()
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)
unset(HEADLESS CACHE)
#unset(TARGET_PLATFORM CACHE)

8
README.md

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

7
alethzero/CMakeLists.txt

@ -20,10 +20,14 @@ if (APPLE)
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(Qt5WebKit REQUIRED)
find_package(Qt5WebKitWidgets REQUIRED)
qt5_wrap_ui(ui_Main.h Main.ui)
# Set name of binary and add_executable()
@ -49,7 +53,7 @@ else ()
add_executable(${EXECUTEABLE} Main.ui ${SRC_LIST})
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})
if (APPLE)
@ -95,6 +99,7 @@ elseif (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(${EXECUTEABLE} crypt32)
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)

168
alethzero/Main.ui

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

301
alethzero/MainWin.cpp

@ -1,11 +1,14 @@
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWebKitWidgets/QWebFrame>
#include <QtGui/QClipboard>
#include <QtCore/QtCore>
#include <libethereum/Dagger.h>
#include <libethereum/Client.h>
#include <libethereum/Instruction.h>
#include <libethereum/PeerServer.h>
#include "BuildInfo.h"
#include "MainWin.h"
#include "ui_Main.h"
@ -30,12 +33,14 @@ using eth::Secret;
using eth::Transaction;
// functions
using eth::asHex;
using eth::toHex;
using eth::assemble;
using eth::compileLisp;
using eth::disassemble;
using eth::formatBalance;
using eth::fromUserHex;
using eth::fromHex;
using eth::sha3;
using eth::left160;
using eth::right160;
using eth::simpleDebugOut;
using eth::toLog2;
@ -51,9 +56,33 @@ static void initUnits(QComboBox* _b)
{
for (auto n = (::uint)units().size(); n-- != 0; )
_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) :
QMainWindow(parent),
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)); };
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);
connect(m_refresh, SIGNAL(timeout()), SLOT(refresh()));
m_refresh->start(100);
@ -119,6 +107,8 @@ Main::Main(QWidget *parent) :
int pocnumber = QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1).toInt();
if (pocnumber == 3)
m_servers.push_back("54.201.28.117:30303");
else if (pocnumber == 4)
m_servers.push_back("54.72.31.55:30303");
else
{
connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r)
@ -132,13 +122,31 @@ Main::Main(QWidget *parent) :
}
#endif
ui->configDock->close();
on_verbosity_sliderMoved();
initUnits(ui->gasPriceUnits);
initUnits(ui->valueUnits);
ui->valueUnits->setCurrentIndex(6);
ui->gasPriceUnits->setCurrentIndex(4);
ui->gasPrice->setValue(10);
on_destination_textChanged();
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
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()
@ -149,7 +157,15 @@ Main::~Main()
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);
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());
memset(n.data() + sn.size(), 0, 32 - sn.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);
}
if (_a.size() == 40)
return Address(fromUserHex(_a.toStdString()));
return Address(fromHex(_a.toStdString()));
else
return Address();
}
@ -246,10 +268,7 @@ void Main::readSettings()
ui->clientName->setText(s.value("clientName", "").toString());
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
if (s.value("nameReg").toString() == "11f62328e131dbb05ce4c73a3de3c7ab1c84a163")
s.remove("nameReg");
ui->nameReg->setText(s.value("nameReg", "8ff91e5b145a23ab1afef34f12587c18bd42aec0").toString());
ui->nameReg->setText(s.value("NameReg", "").toString());
}
void Main::on_nameReg_textChanged()
@ -257,9 +276,11 @@ void Main::on_nameReg_textChanged()
string s = ui->nameReg->text().toStdString();
if (s.size() == 40)
{
m_nameReg = Address(fromUserHex(s));
m_nameReg = Address(fromHex(s));
refresh(true);
}
else
m_nameReg = Address();
}
void Main::refreshNetwork()
@ -319,7 +340,7 @@ void Main::refresh(bool _override)
QString("%2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender()))
.arg(render(right160(t.sha3())))
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce)))))
.arg((unsigned)t.nonce);
ui->transactionQueue->addItem(s);
}
@ -345,7 +366,7 @@ void Main::refresh(bool _override)
QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender()))
.arg(render(right160(t.sha3())))
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce)))))
.arg((unsigned)t.nonce);
QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks);
txItem->setData(Qt::UserRole, QByteArray((char const*)h.data(), h.size));
@ -360,14 +381,19 @@ void Main::refresh(bool _override)
m_keysChanged = false;
ui->ourAccounts->clear();
u256 totalBalance = 0;
u256 totalGavCoinBalance = 0;
Address gavCoin("91a10664d0cd489085a7a018beb5245d4f2272f1");
for (auto i: m_myKeys)
{
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))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
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();
}
@ -422,23 +448,30 @@ void Main::on_blocks_currentItemChanged()
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
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 << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
auto ss = tx.safeSender();
s << "<br/>From: <b>" << pretty(ss).toStdString() << "</b> " << ss;
if (tx.receiveAddress)
s << "<br/>To: <b>" << pretty(tx.receiveAddress).toStdString() << "</b> " << tx.receiveAddress;
else
if (tx.isCreation())
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 << "&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;";
// for (auto i: tx.data)
// s << "0x<b>" << hex << i << "</b>&emsp;";
s << "</br>" << disassemble(tx.data);
if (tx.init.size())
s << "<h4>Init</h4>" << disassemble(tx.init);
if (tx.data.size())
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);
stringstream s;
auto mem = state().contractMemory(h);
u256 next = 0;
unsigned numerics = 0;
bool unexpectedNumeric = false;
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;
}
auto mem = state().contractStorage(h);
for (auto const& i: mem)
s << "@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << i.second << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(state().contractCode(h));
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
}
m_client->unlock();
@ -511,7 +511,7 @@ void Main::on_ourAccounts_doubleClicked()
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
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()
@ -523,14 +523,14 @@ void Main::on_accounts_doubleClicked()
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray())));
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
void Main::on_contracts_doubleClicked()
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray())));
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
void Main::on_destination_textChanged()
@ -542,27 +542,98 @@ void Main::on_destination_textChanged()
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
updateFee();
on_data_textChanged();
// updateFee();
}
void Main::on_data_textChanged()
{
string code = ui->data->toPlainText().toStdString();
m_data = code[0] == '(' ? compileLisp(code, true) : assemble(code, true);
ui->code->setPlainText(QString::fromStdString(disassemble(m_data)));
if (isCreation())
{
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();
}
bool Main::isCreation() const
{
return ui->destination->text().isEmpty()/* || !ui->destination->text().toInt()*/;
}
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
{
if (ui->valueUnits->currentIndex() == -1)
return 0;
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
{
return value() + fee();
@ -570,7 +641,7 @@ u256 Main::total() const
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();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
@ -644,12 +715,14 @@ void Main::on_send_clicked()
u256 totalReq = value() + fee();
m_client->lock();
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq )
if (m_client->state().balance(i.address()) >= totalReq)
{
m_client->unlock();
Secret s = i.secret();
Address r = fromString(ui->destination->text());
m_client->transact(s, r, value(), m_data);
if (isCreation())
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();
return;
}

23
alethzero/MainWin.h

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

161
eth/main.cpp

@ -23,15 +23,19 @@
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include "Defaults.h"
#include "Client.h"
#include "PeerNetwork.h"
#include "BlockChain.h"
#include "State.h"
#include "FileSystem.h"
#include "Instruction.h"
#include "BuildInfo.h"
using namespace std;
using namespace eth;
using eth::Instruction;
using eth::c_instructionInfo;
bool isTrue(std::string const& _m)
{
@ -68,6 +72,32 @@ void help()
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()
{
cout << "eth version " << ETH_QUOTED(ETH_VERSION) << endl;
@ -75,12 +105,30 @@ void version()
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)
{
unsigned short listenPort = 30303;
string remoteHost;
unsigned short remotePort = 30303;
bool interactive = false;
string dbPath;
eth::uint mining = ~(eth::uint)0;
NodeMode mode = NodeMode::Full;
@ -138,11 +186,9 @@ int main(int argc, char** argv)
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
coinbase = h160(fromUserHex(argv[++i]));
coinbase = h160(fromHex(argv[++i]));
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromUserHex(argv[++i])));
else if (arg == "-i" || arg == "--interactive")
interactive = true;
us = KeyPair(h256(fromHex(argv[++i])));
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
@ -188,102 +234,19 @@ int main(int argc, char** argv)
if (!clientName.empty())
clientName += "/";
Client c("Ethereum(++)/" + clientName + "v" ETH_QUOTED(ETH_VERSION) "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath);
if (interactive)
{
cout << "Ethereum (++)" << endl;
cout << " Code by Gav Wood, (c) 2013, 2014." << endl;
cout << " Based on a design by Vitalik Buterin." << endl << endl;
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 << credits();
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
eth::uint n = c.blockChain().details().number;
if (mining)
c.startMining();
while (true)
{
cout << "Address: " << endl << asHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
eth::uint n = c.blockChain().details().number;
if (mining)
c.startMining();
while (true)
{
if (c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
if (c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
return 0;
}

8
libethereum/AddressState.cpp

@ -20,6 +20,14 @@
*/
#include "AddressState.h"
#include "CommonEth.h"
using namespace std;
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
{
public:
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_haveMemory(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, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(false), m_contractRoot(_contractRoot) {}
AddressState(u256 _balance, u256 _nonce, u256s _memory): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true)
{
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
}
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_isComplete(true) {}
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, bytesConstRef _code);
void incNonce() { m_nonce++; }
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
@ -65,20 +51,25 @@ public:
u256 const& balance() const { return m_balance; }
u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; }
bool haveMemory() const { return m_haveMemory; }
std::map<u256, u256>& setHaveMemory() { assert(m_type == AddressType::Contract); m_haveMemory = true; m_contractRoot = h256(); return m_memory; }
h256 oldRoot() const { assert(!haveMemory()); return m_contractRoot; }
std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
bool isComplete() const { return m_isComplete; }
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(!isComplete()); return m_contractRoot; }
h256 codeHash() const { assert(m_codeHash); return m_codeHash; }
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:
AddressType m_type;
u256 m_balance;
u256 m_nonce;
bool m_haveMemory;
bool m_isComplete;
h256 m_contractRoot;
h256 m_codeHash; // if 0 and m_isComplete, has been created and needs to be inserted.
// TODO: change to unordered_map.
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")
{
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;
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.";
// This might be the new last block...
// This might be the new best block...
if (td > details(m_lastBlockHash).totalDifficulty)
{
m_lastBlockHash = newHash;

3
libethereum/BlockChain.h

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

13
libethereum/CMakeLists.txt

@ -10,7 +10,9 @@ if(APPLE)
else()
add_library(ethereum ${SRC_LIST})
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")
include_directories(../secp256k1)
@ -39,6 +41,15 @@ elseif (APPLE)
target_link_libraries(ethereum boost_thread-mt)
find_package(Threads REQUIRED)
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 ()
target_link_libraries(ethereum ${CRYPTOPP_LIBRARIES})
target_link_libraries(ethereum boost_system)

59
libethereum/Client.cpp

@ -26,6 +26,7 @@
#include <boost/filesystem.hpp>
#include "Common.h"
#include "Defaults.h"
#include "PeerServer.h"
using namespace std;
using namespace eth;
@ -51,7 +52,7 @@ void VersionChecker::setOk()
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath):
m_clientVersion(_clientVersion),
m_vc(_dbPath, PeerSession::protocolVersion()),
m_vc(_dbPath, PeerServer::protocolVersion()),
m_bc(_dbPath, !m_vc.ok()),
m_stateDB(State::openDB(_dbPath, !m_vc.ok())),
m_preMine(_us, m_stateDB),
@ -61,11 +62,6 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
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;
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)
work();
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())
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);
if (_seedHost.size())
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)
{
if (!m_net.get())
@ -120,13 +141,15 @@ void Client::stopMining()
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);
Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = _dest;
t.value = _amount;
t.data = _data;
t.sign(_secret);
cnote << "New transaction " << t;
@ -134,6 +157,24 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data)
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()
{
bool changed = false;

19
libethereum/Client.h

@ -83,8 +83,15 @@ public:
/// Destructor.
~Client();
/// Executes the given transaction.
void transact(Secret _secret, Address _dest, u256 _amount, u256s _data = u256s());
/// Submits the given message-call transaction.
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.
void setInterest(Address _dest);
@ -125,9 +132,9 @@ public:
// Network stuff:
/// 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.
size_t peerCount() const { return m_net ? m_net->peerCount() : 0; }
size_t peerCount() const;
/// 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);
@ -135,6 +142,8 @@ public:
void connect(std::string const& _seedHost, unsigned short _port = 30303);
/// Stop the network subsystem.
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.
PeerServer* peerServer() const { return m_net.get(); }
@ -148,6 +157,8 @@ public:
void startMining();
/// Stop mining.
void stopMining();
/// Are we mining now?
bool isMining() { return m_doMine; }
/// Check the progress of the mining.
MineProgress miningProgress() const { return m_mineProgress; }

280
libethereum/Common.cpp

@ -21,285 +21,5 @@
#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 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>
* @date 2014
*
* Shared algorithms and data types.
* Very common stuff (i.e. that every other header needs except vector_ref.h).
*/
#pragma once
// 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
#ifdef _M_IX86
@ -36,27 +36,16 @@
#define noexcept throw()
#endif
#include <ctime>
#include <chrono>
#include <array>
#include <map>
#include <unordered_map>
#include <vector>
#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/thread.hpp>
#include "vector_ref.h"
// CryptoPP defines byte in the global namespace, so so must we.
using byte = uint8_t;
// Quote a given token stream to turn it into a string.
#define ETH_QUOTED_HELPER(s) #s
#define ETH_QUOTED(s) ETH_QUOTED_HELPER(s)
@ -81,132 +70,6 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>;
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.
using StringMap = std::map<std::string, std::string>;
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 bytes NullBytes;
/// Logging
class NullOutputStream
{
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);
}
/// Trivial UnitTest type that everyone can agree on, mainly to allow befriending for test classes & their code.
template <unsigned T> class UnitTest {};
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 <chrono>
#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 "CryptoHeaders.h"
#include "Common.h"
#include "Dagger.h"
using namespace std;

3
libethereum/Dagger.h

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

14
libethereum/Exceptions.h

@ -1,7 +1,9 @@
#pragma once
#include <exception>
#include "Common.h"
#include "CommonIO.h"
#include "CommonData.h"
#include "FixedHash.h"
namespace eth
{
@ -24,20 +26,22 @@ class VMException: public Exception {};
class StepsDone: public VMException {};
class BreakPointHit: 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 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 ContractAddressCollision: public Exception {};
class FeeTooSmall: 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 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 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 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) + " (" + 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) + " (" + toHex(m_d) + ")"; } };
class InvalidUnclesHash: public Exception {};
class InvalidUncle: 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 InvalidDifficulty: public Exception {};
class InvalidTimestamp: public Exception {};

43
libethereum/ExtVMFace.h

@ -35,41 +35,52 @@ class ExtVMFace
public:
ExtVMFace() {}
ExtVMFace(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
fees(_fees),
ExtVMFace(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
previousBlock(_previousBlock),
currentBlock(_currentBlock),
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),
txSender(_txSender),
txValue(_txValue),
txData(_txData),
fees(_fees),
caller(_caller),
origin(_origin),
value(_value),
gasPrice(_gasPrice),
data(_data),
code(_code),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
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; }
void setStore(u256 _n, u256 _v) {}
void mktx(Transaction& _t) {}
u256 balance(Address _a) { return 0; }
void payFee(bigint _fee) {}
void subBalance(u256 _a) {}
u256 txCount(Address _a) { return 0; }
u256 extro(Address _a, u256 _pos) { return 0; }
u256 extroPrice(Address _a) { return 0; }
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 txSender;
u256 txValue;
u256s txData;
FeeStructure fees;
Address caller;
Address origin;
u256 value;
u256 gasPrice;
bytesConstRef data;
bytesConstRef code;
BlockInfo previousBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information.
uint currentNumber;
};

32
libethereum/FeeStructure.cpp

@ -24,26 +24,12 @@
using namespace std;
using namespace eth;
u256 const c_stepFee = 1;
u256 const c_dataFee = 20;
u256 const c_memoryFee = 5;
u256 const c_extroFee = 40;
u256 const c_cryptoFee = 20;
u256 const c_newContractFee = 100;
u256 const c_txFee = 100;
void FeeStructure::setMultiplier(u256 _x)
{
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;
}
u256 const eth::c_stepGas = 1;
u256 const eth::c_balanceGas = 20;
u256 const eth::c_sha3Gas = 20;
u256 const eth::c_sloadGas = 20;
u256 const eth::c_sstoreGas = 100;
u256 const eth::c_createGas = 100;
u256 const eth::c_callGas = 20;
u256 const eth::c_memoryGas = 1;
u256 const eth::c_txDataGas = 5;

22
libethereum/FeeStructure.h

@ -26,18 +26,14 @@
namespace eth
{
struct FeeStructure
{
/// The fee structure. Values yet to be agreed on...
void setMultiplier(u256 _x); ///< The current block multiplier.
u256 multiplier() const;
u256 m_stepFee;
u256 m_dataFee;
u256 m_memoryFee;
u256 m_extroFee;
u256 m_cryptoFee;
u256 m_newContractFee;
u256 m_txFee;
};
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.
extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
extern u256 const c_sloadGas; ///< Once per SLOAD operation.
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).
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
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.
extern u256 const c_txDataGas; ///< Per byte of data attached to a message-call transaction. NOTE: Not payable on data of calls between transactions.
}

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,
NEG,
LT,
LE,
GT,
GE,
EQ,
NOT,
MYADDRESS, ///< pushes the transaction sender
TXSENDER, ///< pushes the transaction sender
TXVALUE , ///< pushes the transaction value
TXDATAN, ///< pushes the number of data items
TXDATA, ///< pops one item and pushes data item S[-1], or zero if index out of range
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
BLK_TIMESTAMP, ///< pushes the timestamp of the current block
BLK_NUMBER, ///< pushes the current block number
BLK_DIFFICULTY, ///< pushes the difficulty of the current block
BLK_NONCE,
BASEFEE,
SHA256 = 0x20,
RIPEMD160,
ECMUL,
ECADD,
ECSIGN,
ECRECOVER,
ECVALID,
SHA3,
PUSH = 0x30,
POP,
AND = 0x10,
OR,
XOR,
BYTE,
SHA3 = 0x20,
ADDRESS = 0x30,
BALANCE,
ORIGIN,
CALLER,
CALLVALUE,
CALLDATALOAD,
CALLDATASIZE,
GASPRICE,
PREVHASH = 0x40,
COINBASE,
TIMESTAMP,
NUMBER,
DIFFICULTY,
GASLIMIT,
POP = 0x50,
DUP,
SWAP,
MLOAD,
MSTORE,
MSTORE8,
SLOAD,
SSTORE,
JMP,
JMPI,
IND,
EXTRO,
BALANCE,
MKTX,
SUICIDE = 0x3f
JUMP,
JUMPI,
PC,
MEMSIZE,
GAS,
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
{
char const* name;
int additional;
int args;
int ret;
char const* name; ///< The name of the instruction.
int additional; ///< Additional items required in memory for this instructions (only for PUSH).
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; ///< 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;
/// Convert from string mnemonic to Instruction type.
extern const std::map<std::string, Instruction> c_instructions;
u256s assemble(std::string const& _code, bool _quiet = false);
std::string disassemble(u256s const& _mem);
u256s compileLisp(std::string const& _code, bool _quiet = false);
/// Convert from simple EVM assembly language to EVM code.
bytes assemble(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
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Miscellanea required for the PeerServer/PeerSession classes.
*/
#pragma once
#include <map>
#include <memory>
#include <utility>
#include <string>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <thread>
#include "RLP.h"
#include <chrono>
#include "Common.h"
#include "Log.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@ -37,8 +37,11 @@ namespace eth
bool isPrivateAddress(bi::address _addressToCheck);
class Overlay;
class BlockChain;
class TransactionQueue;
class PeerServer;
class PeerSession;
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; };
@ -76,7 +79,8 @@ enum DisconnectReason
ClientQuit
};
class PeerServer;
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
struct PeerInfo
{
@ -86,63 +90,7 @@ struct PeerInfo
std::chrono::steady_clock::duration lastPing;
};
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(); }
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;
};
class UPnP;
enum class NodeMode
{
@ -150,99 +98,4 @@ enum class NodeMode
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); }
/// 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> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
/// Appends a list.
RLPStream& appendList(uint _items);
@ -324,14 +325,6 @@ private:
*(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.
bytes m_out;

316
libethereum/State.cpp

@ -42,10 +42,10 @@ std::map<Address, AddressState> const& eth::genesisState()
if (s_ret.empty())
{
// Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
}
return s_ret;
}
@ -56,6 +56,9 @@ Overlay State::openDB(std::string _path, bool _killExisting)
_path = Defaults::get()->m_dbPath;
boost::filesystem::create_directory(_path);
if (_killExisting)
boost::filesystem::remove_all(_path + "/state");
ldb::Options o;
o.create_if_missing = true;
ldb::DB* db = nullptr;
@ -69,7 +72,6 @@ State::State(Address _coinbaseAddress, Overlay const& _db):
m_ourAddress(_coinbaseAddress)
{
m_blockReward = 1500 * finney;
m_fees.setMultiplier(100 * szabo);
secp256k1_start();
@ -95,7 +97,6 @@ State::State(State const& _s):
m_currentBlock(_s.m_currentBlock),
m_currentNumber(_s.m_currentNumber),
m_ourAddress(_s.m_ourAddress),
m_fees(_s.m_fees),
m_blockReward(_s.m_blockReward)
{
}
@ -111,15 +112,19 @@ State& State::operator=(State const& _s)
m_currentBlock = _s.m_currentBlock;
m_currentNumber = _s.m_currentNumber;
m_ourAddress = _s.m_ourAddress;
m_fees = _s.m_fees;
m_blockReward = _s.m_blockReward;
return *this;
}
void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{
auto it = m_cache.find(_a);
if (it == m_cache.end())
ensureCached(m_cache, _a, _requireMemory, _forceCreate);
}
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.
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)
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>());
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;
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.
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! :)
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)
#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>();
#endif
}
}
@ -365,6 +363,7 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _
u256 tdIncrease = m_currentBlock.difficulty;
// Check uncles & apply their rewards to state.
// TODO: Check for uniqueness of uncles.
Addresses rewarded;
for (auto const& i: RLP(_block)[2])
{
@ -567,13 +566,13 @@ u256 State::transactionsFrom(Address _id) const
return it->second.nonce();
}
u256 State::contractMemory(Address _id, u256 _memory) const
u256 State::contractStorage(Address _id, u256 _memory) const
{
ensureCached(_id, false, false);
auto it = m_cache.find(_id);
if (it == m_cache.end() || it->second.type() != AddressType::Contract)
return 0;
else if (it->second.haveMemory())
else if (it->second.isComplete())
{
auto mit = it->second.memory().find(_memory);
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;
}
map<u256, u256> const& State::contractMemory(Address _contract) const
map<u256, u256> const& State::contractStorage(Address _contract) const
{
if (!isContractAddress(_contract))
return EmptyMapU256U256;
@ -594,144 +593,209 @@ map<u256, u256> const& State::contractMemory(Address _contract) const
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)
{
// Entry point for a user-executed transaction.
Transaction t(_rlp);
executeBare(t, t.sender());
// Add to the user-originated transactions that we've executed.
// 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());
}
auto sender = t.sender();
void State::applyRewards(Addresses const& _uncleAddresses)
{
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
// Avoid invalid transactions.
auto nonceReq = transactionsFrom(sender);
if (t.nonce != nonceReq)
{
addBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
clog(StateChat) << "Invalid Nonce.";
throw InvalidNonce(nonceReq, t.nonce);
}
addBalance(m_currentBlock.coinbaseAddress, r);
}
void State::unapplyRewards(Addresses const& _uncleAddresses)
{
u256 r = m_blockReward;
for (auto const& i: _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)
{
subBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
clog(StateChat) << "Offered gas-price is too low.";
throw GasPriceTooLow();
}
subBalance(m_currentBlock.coinbaseAddress, r);
}
void State::executeBare(Transaction const& _t, Address _sender)
{
#if ETH_DEBUG
commit();
clog(StateChat) << "State:" << rootHash();
clog(StateChat) << "Executing TX:" << _t;
#endif
// Entry point for a contract-originated transaction.
// Check gas cost is enough.
u256 gasCost;
if (t.isCreation())
gasCost = (t.init.size() + t.data.size()) * c_txDataGas + c_createGas;
else
gasCost = t.data.size() * c_txDataGas + c_callGas;
// Ignore invalid transactions.
auto nonceReq = transactionsFrom(_sender);
if (_t.nonce != nonceReq)
if (t.gas < gasCost)
{
clog(StateChat) << "Invalid Nonce.";
throw InvalidNonce(nonceReq, _t.nonce);
clog(StateChat) << "Not enough gas to pay for the transaction.";
throw OutOfGas();
}
unsigned nonZeroData = 0;
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);
u256 cost = t.value + t.gas * t.gasPrice;
// Not considered invalid - just pointless.
if (balance(_sender) < _t.value + fee)
// Avoid unaffordable transactions.
if (balance(sender) < cost)
{
clog(StateChat) << "Not enough cash.";
throw NotEnoughCash();
}
if (_t.receiveAddress)
{
// Increment associated nonce for sender.
noteSending(_sender);
u256 gas = t.gas - gasCost;
// Pay...
subBalance(_sender, _t.value + fee);
addBalance(_t.receiveAddress, _t.value);
// Increment associated nonce for sender.
noteSending(sender);
if (isContractAddress(_t.receiveAddress))
{
// Once we get here, there's no going back.
try
{
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction.
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();
}
}
}
// Pay...
cnote << "Paying" << formatBalance(cost) << "from sender (includes" << t.gas << "gas at" << formatBalance(t.gasPrice) << ")";
subBalance(sender, cost);
if (t.isCreation())
create(sender, t.value, t.gasPrice, &gas, &t.data, &t.init);
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.";
throw ContractAddressCollision();
clog(StateChat) << "std::exception in VM: " << _e.what();
}
// Increment associated nonce for sender.
noteSending(_sender);
// Write state out only in the case of a non-excepted transaction.
if (revert)
evm.revert();
// Pay out of sender...
subBalance(_sender, _t.value + fee);
*_gas = vm.gas();
// Set up new account...
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 !revert;
}
return true;
}
#if ETH_DEBUG
commit();
clog(StateChat) << "New state:" << rootHash();
#endif
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init, Address _origin)
{
if (!_origin)
_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;
ExtVM evm(*this, _myAddress, _txSender, _txValue, _txData);
vm.go(evm);
*_totalFee = vm.runFee();
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
{
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 bytes EmptyBytes;
struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; };
class ExtVM;
@ -76,7 +78,7 @@ public:
Address address() const { return m_ourAddress; }
/// 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); }
/// @returns the set containing all addresses currently in use in Ethereum.
@ -119,6 +121,7 @@ public:
bool cull(TransactionQueue& _tq) const;
/// 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(bytesConstRef _rlp);
@ -144,11 +147,15 @@ public:
/// Get the value of a memory position of a contract.
/// @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.
/// @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.
void noteSending(Address _id);
@ -170,26 +177,21 @@ public:
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.
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.
u256 fee() const { return m_fees.m_txFee; }
u256 callGas(uint _dataCount, u256 _gas = 0) const { return c_txDataGas * _dataCount + c_callGas + _gas; }
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.
/// 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
/// exist in the DB.
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.
void commit();
@ -201,12 +203,16 @@ private:
/// Throws on failure.
u256 playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit);
/// Execute a decoded transaction object, given a sender.
/// This will append @a _t to the transaction list and change the state accordingly.
void executeBare(Transaction const& _t, Address _sender);
// Two priviledged entry points for transaction processing used by the VM (these don't get added to the Transaction lists):
// We assume all instrinsic fees are paid up before this point.
/// 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.
void execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* o_totalFee);
/// Execute a call.
/// @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).
void resetCurrent();
@ -236,7 +242,6 @@ private:
Dagger m_dagger;
FeeStructure m_fees;
u256 m_blockReward;
static std::string c_defaultPath;
@ -247,8 +252,8 @@ private:
class ExtVM: public ExtVMFace
{
public:
ExtVM(State& _s, Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData):
ExtVMFace(_myAddress, _txSender, _txValue, _txData, _s.m_fees, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s)
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code):
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_store = &(m_s.m_cache[_myAddress].memory());
@ -262,45 +267,41 @@ public:
void setStore(u256 _n, u256 _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;
#endif
}
else
m_store->erase(_n);
}
void payFee(bigint _f)
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{
if (_f > m_s.balance(myAddress))
throw NotEnoughCash();
m_s.subBalance(myAddress, _f);
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
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);
m_s.executeBare(_t, myAddress);
return m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin);
}
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 extro(Address _a, u256 _pos) { return m_s.contractMemory(_a, _pos); }
u256 extroPrice(Address _a) { return 0; }
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();
}
void revert()
{
m_s.m_cache = m_origCache;
}
private:
State& m_s;
std::map<Address, AddressState> m_origCache;
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;
for (auto const& j: memdb)
{
_out << std::endl << " [" << j.first << ":" << asHex(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
_out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
mem[j.first] = RLP(j.second).toInt<u256>();
#endif
}
_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();
if (i.second.type() == AddressType::Contract)
{
if (i.second.haveMemory())
if (i.second.isComplete())
{
_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;
for (auto const& j: memdb)
{
_out << std::endl << " [" << j.first << ":" << asHex(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
_out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
mem[j.first] = RLP(j.second).toInt<u256>();
#endif
}
_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();
if (i.second.type() == AddressType::Contract)
{
if (i.second.haveMemory())
if (i.second.isComplete())
{
TrieDB<h256, DB> memdb(&_db);
memdb.init();
@ -398,9 +383,17 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
if (j.second)
memdb.insert(j.first, rlp(j.second));
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
s << i.second.oldRoot();
s << i.second.oldRoot() << i.second.codeHash();
}
_state.insert(i.first, &s.out());
}

27
libethereum/Transaction.cpp

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

31
libethereum/Transaction.h

@ -21,7 +21,7 @@
#pragma once
#include "Common.h"
#include "CommonEth.h"
#include "RLP.h"
namespace eth
@ -34,7 +34,9 @@ struct Signature
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
{
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 !operator==(_c); }
u256 nonce;
Address receiveAddress;
u256 value;
u256s data;
Signature vrs;
u256 nonce; ///< The transaction-count of the sender.
u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions.
Address receiveAddress; ///< The receiving address of the transaction.
u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS.
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;
Address sender() const;
void sign(Secret _priv);
bytes data; ///< The data associated with the transaction, or the main body if it's a creation transaction.
bytes init; ///< The initialisation associated with the transaction.
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);
@ -73,7 +82,7 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t)
else
_out << "[CREATE]";
_out << "/" << _t.nonce << "*" << _t.value;
_out << "/" << _t.nonce << "$" << _t.value << "+" << _t.gas << "@" << _t.gasPrice;
Address s;
try
{

1
libethereum/TransactionQueue.cpp

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

16
libethereum/TrieDB.h

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

1
libethereum/UPnP.cpp

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

30
libethereum/VM.cpp

@ -21,38 +21,12 @@
#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 eth;
VM::VM()
{
reset();
}
void VM::reset()
void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
m_nextPC = 1;
m_stepCount = 0;

568
libethereum/VM.h

@ -22,21 +22,7 @@
#pragma once
#include <unordered_map>
#include <secp256k1.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 "CommonEth.h"
#include "Exceptions.h"
#include "FeeStructure.h"
#include "Instruction.h"
@ -56,6 +42,9 @@ inline Address asAddress(u256 _item)
inline u256 fromAddress(Address _a)
{
return (u160)_a;
// h256 ret;
// memcpy(&ret, &_a, sizeof(_a));
// return ret;
}
/**
@ -66,21 +55,24 @@ class VM
public:
/// Construct VM object.
VM();
explicit VM(u256 _gas = 0) { reset(_gas); }
void reset();
void reset(u256 _gas = 0);
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 requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 runFee() const { return m_runFee; }
u256 gas() const { return m_gas; }
private:
u256 m_gas = 0;
u256 m_curPC = 0;
u256 m_nextPC = 1;
uint64_t m_stepCount = 0;
std::map<u256, u256> m_temp;
bytes m_temp;
std::vector<u256> m_stack;
u256 m_runFee = 0;
};
@ -88,57 +80,109 @@ private:
}
// 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)
{
m_stepCount++;
// INSTRUCTION...
auto rawInst = _ext.store(m_curPC);
if (rawInst > 0xff)
throw BadInstruction();
Instruction inst = (Instruction)(uint8_t)rawInst;
Instruction inst = (Instruction)_ext.getCode(m_curPC);
// FEES...
bigint runFee = m_stepCount > 16 ? _ext.fees.m_stepFee : 0;
bigint storeCostDelta = 0;
bigint runGas = c_stepGas;
unsigned newTempSize = (unsigned)m_temp.size();
switch (inst)
{
case Instruction::STOP:
runGas = 0;
break;
case Instruction::SSTORE:
require(2);
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
storeCostDelta += _ext.fees.m_memoryFee;
if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
storeCostDelta -= _ext.fees.m_memoryFee;
// continue on to...
runGas = c_sstoreGas * 2;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
runGas = 0;
else
runGas = c_sstoreGas;
break;
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;
case Instruction::EXTRO:
case Instruction::BALANCE:
runFee += _ext.fees.m_extroFee;
runGas = c_balanceGas;
break;
case Instruction::MKTX:
runFee += _ext.fees.m_txFee;
case Instruction::CALL:
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;
case Instruction::SHA256:
case Instruction::RIPEMD160:
case Instruction::ECMUL:
case Instruction::ECADD:
case Instruction::ECSIGN:
case Instruction::ECRECOVER:
case Instruction::ECVALID:
runFee += _ext.fees.m_cryptoFee;
case Instruction::CREATE:
{
require(3);
u256 gas = (unsigned)m_stack[m_stack.size() - 1];
unsigned inOff = (unsigned)m_stack[m_stack.size() - 2];
unsigned inSize = (unsigned)m_stack[m_stack.size() - 3];
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;
}
default:
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...
switch (inst)
@ -162,21 +206,29 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
break;
case Instruction::DIV:
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.pop_back();
break;
case Instruction::SDIV:
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];
m_stack.pop_back();
break;
case Instruction::MOD:
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.pop_back();
break;
case Instruction::SMOD:
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];
m_stack.pop_back();
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.pop_back();
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:
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::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:
require(2);
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);
m_stack.back() = m_stack.back() ? 0 : 1;
break;
case Instruction::MYADDRESS:
m_stack.push_back(fromAddress(_ext.myAddress));
break;
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);
case Instruction::AND:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2];
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;
}
case Instruction::RIPEMD160:
{
require(1);
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
case Instruction::OR:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2];
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;
}
case Instruction::ECMUL:
{
// 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());
case Instruction::XOR:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2];
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;
}
case Instruction::ECADD:
{
// 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();
case Instruction::BYTE:
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;
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;
}
case Instruction::ECSIGN:
case Instruction::SHA3:
{
require(2);
bytes sig(64);
int v = 0;
u256 msg = m_stack.back();
unsigned inOff = (unsigned)m_stack.back();
m_stack.pop_back();
u256 priv = m_stack.back();
unsigned inSize = (unsigned)m_stack.back();
m_stack.pop_back();
bytes nonce = toBigEndian(Transaction::kFromMessage(msg, priv));
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)));
m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize)));
break;
}
case Instruction::ECRECOVER:
{
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)));
}
case Instruction::ADDRESS:
m_stack.push_back(fromAddress(_ext.myAddress));
break;
}
case Instruction::ECVALID:
case Instruction::ORIGIN:
m_stack.push_back(fromAddress(_ext.origin));
break;
case Instruction::BALANCE:
{
require(2);
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();
m_stack.back() = secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size()) ? 1 : 0;
require(1);
m_stack.back() = _ext.balance(asAddress(m_stack.back()));
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);
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
m_stack.pop_back();
CryptoPP::SHA3_256 digest;
uint i = 0;
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
if ((unsigned)m_stack.back() + 32 < _ext.data.size())
m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
else
{
bytes b = toBigEndian(m_stack.back());
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
m_stack.pop_back();
h256 r;
for (unsigned i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + 32, j = 0; i < e; ++i, ++j)
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;
}
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));
m_nextPC = m_curPC + 2;
int i = (int)inst - (int)Instruction::PUSH1 + 1;
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;
}
case Instruction::POP:
@ -484,29 +433,21 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::MLOAD:
{
require(1);
#ifdef __clang__
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
m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back());
break;
}
case Instruction::MSTORE:
{
require(2);
#ifdef __clang__
auto mFinder = m_temp.find(m_stack.back());
if (mFinder == m_temp.end())
m_temp.insert(std::make_pair(m_stack.back(), m_stack[m_stack.size() - 2]));
else
mFinder->second = m_stack[m_stack.size() - 2];
#else
m_temp[m_stack.back()] = m_stack[m_stack.size() - 2];
#endif
*(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2];
m_stack.pop_back();
m_stack.pop_back();
break;
}
case Instruction::MSTORE8:
{
require(2);
m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff);
m_stack.pop_back();
m_stack.pop_back();
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();
break;
case Instruction::JMP:
case Instruction::JUMP:
require(1);
m_nextPC = m_stack.back();
m_stack.pop_back();
break;
case Instruction::JMPI:
case Instruction::JUMPI:
require(2);
if (m_stack.back())
m_nextPC = m_stack[m_stack.size() - 2];
if (m_stack[m_stack.size() - 2])
m_nextPC = m_stack.back();
m_stack.pop_back();
m_stack.pop_back();
break;
case Instruction::IND:
case Instruction::PC:
m_stack.push_back(m_curPC);
break;
case Instruction::EXTRO:
{
require(2);
auto memoryAddress = m_stack.back();
m_stack.pop_back();
Address contractAddress = asAddress(m_stack.back());
m_stack.back() = _ext.extro(contractAddress, memoryAddress);
case Instruction::MEMSIZE:
m_stack.push_back(m_temp.size());
break;
}
case Instruction::BALANCE:
case Instruction::GAS:
m_stack.push_back(m_gas);
break;
case Instruction::CREATE:
{
require(1);
m_stack.back() = _ext.balance(asAddress(m_stack.back()));
require(5);
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;
}
case Instruction::MKTX:
case Instruction::CALL:
{
require(3);
require(7);
Transaction t;
t.receiveAddress = asAddress(m_stack.back());
u160 receiveAddress = asAddress(m_stack.back());
m_stack.pop_back();
u256 value = m_stack.back();
m_stack.pop_back();
t.value = m_stack.back();
u256 gas = m_stack.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();
if (m_stack.size() < itemCount)
throw OperandOutOfRange(0, m_stack.size(), itemCount);
t.data.reserve((uint)itemCount);
for (auto i = 0; i < itemCount; ++i)
unsigned outOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned outSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (!gas)
{
t.data.push_back(m_stack.back());
m_stack.pop_back();
gas = m_gas;
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;
}
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:
{
require(1);
@ -583,12 +560,13 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
// ...follow through to...
}
case Instruction::STOP:
return;
return bytesConstRef();
default:
throw BadInstruction();
}
}
if (_steps == (unsigned)-1)
throw StepsDone();
return bytesConstRef();
}

11
libethereum/vector_ref.h

@ -5,14 +5,10 @@
#include <vector>
#include <string>
#if WIN32
#pragma warning(push)
#pragma warning(disable: 4267)
#endif
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#if WIN32
#pragma warning(pop)
#endif
namespace eth
{
@ -23,6 +19,7 @@ class vector_ref
public:
typedef _T value_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(_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; }
bool contentsEqual(std::vector<_T> 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); }
bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.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::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)); }

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_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else ()
target_link_libraries(testeth ${CRYPTOPP_LIBRARIES})
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
*/
#include "Common.h"
#include "TrieCommon.h"
#include "MemTrie.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std;
using namespace eth;
@ -147,7 +148,7 @@ public:
assert(m_value.size());
std::cerr << _indent;
if (m_ext.size())
std::cerr << asHex(m_ext, 1) << ": ";
std::cerr << toHex(m_ext, 1) << ": ";
else
std::cerr << "@: ";
std::cerr << m_value << std::endl;
@ -174,7 +175,7 @@ public:
#if ENABLE_DEBUG_PRINT
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 + " ");
}
#endif
@ -454,7 +455,7 @@ std::string const& MemTrie::at(std::string const& _key) const
{
if (!m_root)
return c_nullString;
auto h = toHex(_key);
auto h = asNibbles(_key);
return m_root->at(bytesConstRef(&h));
}
@ -462,7 +463,7 @@ void MemTrie::insert(std::string const& _key, std::string const& _value)
{
if (_value.empty())
remove(_key);
auto h = toHex(_key);
auto h = asNibbles(_key);
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)
{
auto h = toHex(_key);
auto h = asNibbles(_key);
m_root = m_root->remove(&h);
}
}

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

@ -21,7 +21,8 @@
#pragma once
#include "Common.h"
#include <Common.h>
#include <FixedHash.h>
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
*/
#include "Common.h"
#include "TrieCommon.h"
#include "TrieHash.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std;
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;
#if ENABLE_DEBUG_PRINT
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
}
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 ENABLE_DEBUG_PRINT
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
_rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre);
hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp);
@ -162,7 +163,7 @@ h256 hash256(StringMap const& _s)
return h256();
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second;
hexMap[asNibbles(i->first)] = i->second;
RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out());
@ -175,7 +176,7 @@ bytes rlp256(StringMap const& _s)
return bytes();
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second;
hexMap[asNibbles(i->first)] = i->second;
RLPStream s;
hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return s.out();
@ -188,7 +189,7 @@ h256 hash256(u256Map const& _s)
return h256();
HexMap hexMap;
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;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out());

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

@ -21,7 +21,8 @@
#pragma once
#include "Common.h"
#include <Common.h>
#include <FixedHash.h>
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 <Common.h>
#include <RLP.h>
#include <Log.h>
#include <Transaction.h>
using namespace std;
using namespace eth;
@ -33,21 +34,20 @@ int cryptoTest()
cnote << "Testing Crypto...";
secp256k1_start();
KeyPair p(Secret(fromUserHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
assert(p.pub() == Public(fromUserHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
assert(p.address() == Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
{
Transaction t;
t.nonce = 0;
t.receiveAddress = h160(fromUserHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000;
t.data = u256s();
cnote << RLP(t.rlp(false));
cnote << asHex(t.rlp(false));
cnote << toHex(t.rlp(false));
cnote << t.sha3(false);
t.sign(p.secret());
cnote << RLP(t.rlp(true));
cnote << asHex(t.rlp(true));
cnote << toHex(t.rlp(true));
cnote << t.sha3(true);
assert(t.sender() == p.address());
}
@ -55,7 +55,7 @@ int cryptoTest()
#if 0
// Test transaction.
bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");
bytes tx = fromHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");
cout << "TX: " << RLP(tx) << endl;
Transaction t2(tx);
@ -69,13 +69,13 @@ int cryptoTest()
t.receiveAddress = toAddress(sha3("123"));
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);
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);
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");
@ -84,12 +84,12 @@ int cryptoTest()
int pubkeylen = 65;
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);
pubkey.resize(pubkeylen);
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...
@ -97,17 +97,17 @@ int cryptoTest()
bytes sig(64);
u256 nonce = 0;
int v = 0;
cout << asHex(hmsg) << endl;
cout << asHex(privkey) << endl;
cout << toHex(hmsg) << endl;
cout << toHex(privkey) << 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);
cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << asHex(sig) << " " << v << endl;
cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << toHex(sig) << " " << v << endl;
bytes pubkey(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);
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 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);
cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl;
cout << "SENDER: " << hex << low160(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl;
cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl;
cout << "SENDER: " << hex << toAddress(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl;
}
#endif
return 0;

1
test/dagger.cpp

@ -21,6 +21,7 @@
*/
#include <chrono>
#include "Log.h"
#include "Dagger.h"
using namespace std;
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 "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include "JsonSpiritHeaders.h"
#include "TrieCommon.h"
#include "Log.h"
using namespace std;
using namespace eth;
namespace js = json_spirit;
@ -48,11 +48,11 @@ public:
for (auto& i: o["seq"].get_array())
v.push_back((byte)i.get_int());
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 says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(e);
cwarn << "Impl says:" << toHex(e);
passed = false;
}
}

9
test/main.cpp

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

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 <boost/filesystem/operations.hpp>
#include <BlockChain.h>
#include <PeerNetwork.h>
#include <PeerServer.h>
using namespace std;
using namespace eth;
using boost::asio::ip::tcp;

8
test/rlp.cpp

@ -21,8 +21,8 @@
*/
#include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include "JsonSpiritHeaders.h"
#include <Log.h>
#include <RLP.h>
using namespace std;
using namespace eth;
@ -67,11 +67,11 @@ public:
cnote << i.first;
RLPStream 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 says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(s.out());
cwarn << "Impl says:" << toHex(s.out());
passed = false;
}
}

13
test/trie.cpp

@ -21,12 +21,11 @@
*/
#include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <random>
#include <TrieHash.h>
#include "JsonSpiritHeaders.h"
#include <TrieDB.h>
#include <MemTrie.h>
#include "TrieHash.h"
#include "MemTrie.h"
using namespace std;
using namespace eth;
@ -61,11 +60,11 @@ public:
t.init();
for (auto const& k: ss)
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 says:" << o["root"].get_str();
cwarn << "Impl says:" << asHex(t.root().asArray());
cwarn << "Impl says:" << toHex(t.root().asArray());
passed = false;
}
}
@ -154,7 +153,7 @@ int trieTest()
t.insert("doe", "reindeer");
cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl;
cout << asHex(t.rlp()) << endl;
cout << toHex(t.rlp()) << endl;
}
{
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 "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <ExtVMFace.h>
#include <Transaction.h>
#include <VM.h>
#include <Log.h>
#include <Instruction.h>
#include "JsonSpiritHeaders.h"
using namespace std;
using namespace json_spirit;
using namespace eth;
@ -39,39 +39,27 @@ class FakeExtVM: public ExtVMFace
public:
FakeExtVM()
{}
FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber)
FakeExtVM(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _currentNumber)
{}
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];
#endif
}
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;
#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)
{
@ -81,63 +69,57 @@ public:
txs.push_back(_t);
}
}
u256 balance(Address _a) { return get<0>(addresses[_a]); }
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)
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{
#ifdef __clang__
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a];
map<u256, u256> & third = get<3>(address);
auto sFinder = third.find(_pos);
if (sFinder != third.end())
return sFinder->second;
else
return 0;
#else
return get<3>(addresses[_a])[_pos];
#endif
Transaction t;
t.value = _endowment;
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _code.toBytes();
t.init = _init.toBytes();
txs.push_back(t);
return right160(t.sha3(false));
}
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]))
if (i.second)
get<0>(addresses[_a]) += fees.m_memoryFee;
get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
addresses.erase(myAddress);
Transaction t;
t.value = _value;
t.gasPrice = gasPrice;
t.gas = *_gas;
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;
txValue = _txValue;
txData = _txData;
caller = origin = _caller;
value = _value;
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;
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<1>(addresses[_a]) = _myNonce;
get<2>(addresses[_a]) = 0;
for (unsigned i = 0; i < _myData.size(); ++i)
#ifdef __clang__
{
tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a];
map<u256, u256> & third = get<3>(address);
auto sFinder = third.find(i);
if (sFinder != third.end())
sFinder->second = _myData[i];
else
third.insert(std::make_pair(i, _myData[i]));
}
#else
get<3>(addresses[_a])[i] = _myData[i];
#endif
get<3>(addresses[_a]) = _storage;
get<4>(addresses[_a]) = _code;
}
void reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _storage)
{
txs.clear();
addresses.clear();
set(myAddress, _myBalance, _myNonce, get<4>(addresses[myAddress]), _storage);
}
mObject exportEnv()
@ -148,7 +130,6 @@ public:
push(ret, "currentDifficulty", currentBlock.difficulty);
push(ret, "currentTimestamp", currentBlock.timestamp);
ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress);
push(ret, "feeMultiplier", fees.multiplier());
return ret;
}
@ -159,7 +140,6 @@ public:
currentBlock.difficulty = toInt(_o["currentDifficulty"]);
currentBlock.timestamp = toInt(_o["currentTimestamp"]);
currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
fees.setMultiplier(toInt(_o["feeMultiplier"]));
}
static u256 toInt(mValue const& _v)
@ -175,6 +155,19 @@ public:
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)
{
if (_v < (u256)1 << 64)
@ -199,7 +192,6 @@ public:
mObject o;
push(o, "balance", get<0>(a.second));
push(o, "nonce", get<1>(a.second));
push(o, "extroPrice", get<2>(a.second));
mObject store;
string curKey;
@ -239,42 +231,18 @@ public:
auto& a = addresses[Address(i.first)];
get<0>(a) = toInt(o["balance"]);
get<1>(a) = toInt(o["nonce"]);
get<2>(a) = toInt(o["extroPrice"]);
if (o.count("store"))
for (auto const& j: o["store"].get_obj())
{
u256 adr(j.first);
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);
#endif
}
if (o.count("code"))
{
u256s d = compileLisp(o["code"].get_str());
for (unsigned i = 0; i < d.size(); ++i)
#ifdef __clang__
{
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
bytes e;
bytes d = compileLisp(o["code"].get_str(), false, e);
get<4>(a) = d;
}
}
}
@ -283,10 +251,12 @@ public:
{
mObject ret;
ret["address"] = toString(myAddress);
ret["sender"] = toString(txSender);
push(ret, "value", txValue);
ret["caller"] = toString(caller);
ret["origin"] = toString(origin);
push(ret, "value", value);
push(ret, "gasPrice", gasPrice);
mArray d;
for (auto const& i: txData)
for (auto const& i: data)
push(d, i);
ret["data"] = d;
return ret;
@ -295,10 +265,14 @@ public:
void importExec(mObject& _o)
{
myAddress = Address(_o["address"].get_str());
txSender = Address(_o["sender"].get_str());
txValue = toInt(_o["value"]);
caller = Address(_o["caller"].get_str());
origin = Address(_o["origin"].get_str());
value = toInt(_o["value"]);
gasPrice = toInt(_o["gasPrice"]);
thisTxData.clear();
for (auto const& j: _o["data"].get_array())
txData.push_back(toInt(j));
thisTxData.push_back(toByte(j));
data = &thisTxData;
}
mArray exportTxs()
@ -327,20 +301,14 @@ public:
t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]);
for (auto const& j: tx["data"].get_array())
t.data.push_back(toInt(j));
t.data.push_back(toByte(j));
txs.push_back(t);
}
}
void reset(u256 _myBalance, u256 _myNonce, u256s _myData)
{
txs.clear();
addresses.clear();
set(myAddress, _myBalance, _myNonce, _myData);
}
map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
map<Address, tuple<u256, u256, u256, map<u256, u256>, bytes>> addresses;
Transactions txs;
bytes thisTxData;
};
#define CREATE_TESTS 0
@ -380,21 +348,37 @@ public:
if (_fillin)
o["pre"] = mValue(fev.exportState());
bytes output;
for (auto i: o["exec"].get_array())
{
fev.importExec(i.get_obj());
vm.go(fev);
output = vm.go(fev).toBytes();
}
if (_fillin)
{
o["post"] = mValue(fev.exportState());
o["txs"] = fev.exportTxs();
mArray df;
for (auto const& i: output)
FakeExtVM::push(df, i);
o["out"] = df;
}
else
{
FakeExtVM test;
test.importState(o["post"].get_obj());
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)
{
cwarn << "Test failed: state different.";
@ -424,13 +408,12 @@ public:
cb.difficulty = 256;
cb.timestamp = 1;
cb.coinbaseAddress = toAddress(sha3("coinbase"));
FeeStructure fees;
fees.setMultiplier(1);
FakeExtVM fev(fees, pb, cb, 0);
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
FakeExtVM fev(pb, cb, 0);
bytes init;
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))", false, init), map<u256, u256>());
o["env"] = fev.exportEnv();
o["pre"] = fev.exportState();
fev.setTransaction(toAddress(sha3("sender")), ether, u256s());
fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes());
mArray execs;
execs.push_back(fev.exportExec());
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
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibMiniUPnPc", "LibMiniUPnPc.vcxproj", "{1B1CA20E-39C3-4D9B-AC37-3783048E6672}"
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
Global
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|x64.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

8
windows/LibCryptoPP.vcxproj

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

2
windows/LibEthereum.props

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

31
windows/LibEthereum.vcxproj

@ -28,21 +28,36 @@
<ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\BlockInfo.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\Defaults.cpp" />
<ClCompile Include="..\libethereum\FeeStructure.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\MemTrie.cpp" />
<ClCompile Include="..\libethereum\Log.cpp" />
<ClCompile Include="..\libethereum\PeerNetwork.cpp" />
<ClCompile Include="..\libethereum\PeerServer.cpp" />
<ClCompile Include="..\libethereum\PeerSession.cpp" />
<ClCompile Include="..\libethereum\RLP.cpp" />
<ClCompile Include="..\libethereum\State.cpp" />
<ClCompile Include="..\libethereum\Transaction.cpp" />
<ClCompile Include="..\libethereum\TransactionQueue.cpp" />
<ClCompile Include="..\libethereum\TrieCommon.cpp" />
<ClCompile Include="..\libethereum\TrieDB.cpp" />
<ClCompile Include="..\libethereum\TrieHash.cpp" />
<ClCompile Include="..\libethereum\UPnP.cpp" />
<ClCompile Include="..\libethereum\VM.cpp" />
<ClCompile Include="stdafx.cpp">
@ -59,22 +74,28 @@
<ClInclude Include="..\libethereum\BlockInfo.h" />
<ClInclude Include="..\libethereum\Client.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\Defaults.h" />
<ClInclude Include="..\libethereum\Exceptions.h" />
<ClInclude Include="..\libethereum\ExtVMFace.h" />
<ClInclude Include="..\libethereum\FeeStructure.h" />
<ClInclude Include="..\libethereum\FileSystem.h" />
<ClInclude Include="..\libethereum\FixedHash.h" />
<ClInclude Include="..\libethereum\Instruction.h" />
<ClInclude Include="..\libethereum\MemTrie.h" />
<ClInclude Include="..\libethereum\Log.h" />
<ClInclude Include="..\libethereum\PeerNetwork.h" />
<ClInclude Include="..\libethereum\PeerServer.h" />
<ClInclude Include="..\libethereum\PeerSession.h" />
<ClInclude Include="..\libethereum\RLP.h" />
<ClInclude Include="..\libethereum\State.h" />
<ClInclude Include="..\libethereum\Transaction.h" />
<ClInclude Include="..\libethereum\TransactionQueue.h" />
<ClInclude Include="..\libethereum\TrieCommon.h" />
<ClInclude Include="..\libethereum\TrieDB.h" />
<ClInclude Include="..\libethereum\TrieHash.h" />
<ClInclude Include="..\libethereum\UPnP.h" />
<ClInclude Include="..\libethereum\vector_ref.h" />
<ClInclude Include="..\libethereum\VM.h" />

47
windows/LibEthereum.vcxproj.filters

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

8
windows/LibLevelDB.vcxproj

@ -157,7 +157,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<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>
<Link>
<SubSystem>Windows</SubSystem>
@ -172,7 +172,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<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>
<Link>
<SubSystem>Windows</SubSystem>
@ -189,7 +189,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<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>
<Link>
<SubSystem>Windows</SubSystem>
@ -208,7 +208,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);../../leveldb</AdditionalIncludeDirectories>
<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>
<Link>
<SubSystem>Windows</SubSystem>

8
windows/LibMiniUPnPc.vcxproj

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

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

Loading…
Cancel
Save