Browse Source

Merge branch 'develop' into develop-evmcc

cl-refactor
Paweł Bylica 10 years ago
parent
commit
e0466e2754
  1. 2
      CMakeLists.txt
  2. 2
      alethzero/CMakeLists.txt
  3. 83
      alethzero/DownloadView.cpp
  4. 53
      alethzero/DownloadView.h
  5. 48
      alethzero/Main.ui
  6. 258
      alethzero/MainWin.cpp
  7. 9
      alethzero/MainWin.h
  8. 4
      eth/CMakeLists.txt
  9. 39
      eth/EthStubServer.cpp
  10. 8
      eth/EthStubServer.h
  11. 7
      eth/abstractethstubserver.h
  12. 12
      eth/eth.js
  13. 147
      eth/main.cpp
  14. 310
      exp/main.cpp
  15. 2
      libdevcore/Common.cpp
  16. 178
      libdevcore/CommonData.cpp
  17. 5
      libdevcore/CommonData.h
  18. 20
      libdevcore/CommonIO.h
  19. 5
      libdevcore/RLP.h
  20. 22
      libdevcore/RangeMask.cpp
  21. 212
      libdevcore/RangeMask.h
  22. 63
      libdevcore/Worker.cpp
  23. 59
      libdevcore/Worker.h
  24. 3
      libdevcrypto/FileSystem.cpp
  25. 3
      libdevcrypto/FileSystem.h
  26. 2
      libethcore/BlockInfo.h
  27. 2
      libethcore/CommonEth.cpp
  28. 48
      libethereum/BlockChain.cpp
  29. 8
      libethereum/BlockChain.h
  30. 9
      libethereum/BlockQueue.cpp
  31. 5
      libethereum/BlockQueue.h
  32. 284
      libethereum/Client.cpp
  33. 68
      libethereum/Client.h
  34. 17
      libethereum/CommonNet.h
  35. 75
      libethereum/DownloadMan.cpp
  36. 136
      libethereum/DownloadMan.h
  37. 265
      libethereum/EthereumHost.cpp
  38. 44
      libethereum/EthereumHost.h
  39. 137
      libethereum/EthereumPeer.cpp
  40. 19
      libethereum/EthereumPeer.h
  41. 1
      libethereum/Executive.cpp
  42. 5
      libethereum/Interface.h
  43. 36
      libethereum/Miner.cpp
  44. 24
      libethereum/Miner.h
  45. 5
      libethereum/State.cpp
  46. 2
      libethereum/State.h
  47. 2
      libethereum/TransactionQueue.h
  48. 7
      libevm/VM.h
  49. 261
      libevmface/Instruction.h
  50. 1
      libp2p/Common.h
  51. 151
      libp2p/Host.cpp
  52. 44
      libp2p/Host.h
  53. 4
      libp2p/HostCapability.h
  54. 34
      libp2p/Session.cpp
  55. 2
      libp2p/Session.h
  56. 2
      libqethereum/CMakeLists.txt
  57. 53
      libqethereum/QEthereum.cpp
  58. 11
      libqethereum/QEthereum.h
  59. 4
      libqethereum/QmlEthereum.cpp
  60. 8
      libqethereum/QmlEthereum.h
  61. 58
      libwebthree/WebThree.cpp
  62. 24
      libwebthree/WebThree.h
  63. 2
      libwhisper/WhisperPeer.h
  64. 1
      neth/CMakeLists.txt
  65. 42
      neth/main.cpp
  66. 2
      package.sh
  67. 1
      sc/cmdline.cpp
  68. 3
      test/TestHelper.cpp
  69. 2
      test/peer.cpp
  70. 36
      test/vm.cpp
  71. 2055
      test/vmArithmeticTestFiller.json
  72. 2
      third/CMakeLists.txt
  73. 141
      third/MainWin.cpp
  74. 8
      third/MainWin.h
  75. 2
      walleth/MainWin.cpp
  76. 20
      windows/Alethzero.vcxproj
  77. 2
      windows/Ethereum.sln
  78. 2
      windows/LibEthereum.vcxproj
  79. 6
      windows/LibEthereum.vcxproj.filters

2
CMakeLists.txt

@ -369,7 +369,7 @@ if (NOT LANGUAGES)
add_subdirectory(third) add_subdirectory(third)
if(QTQML) if(QTQML)
#add_subdirectory(iethxi) #add_subdirectory(iethxi)
add_subdirectory(walleth) #add_subdirectory(walleth) // resurect once we want to submit ourselves to QML.
endif() endif()
endif() endif()
endif() endif()

2
alethzero/CMakeLists.txt

@ -52,7 +52,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

83
alethzero/DownloadView.cpp

@ -0,0 +1,83 @@
/*
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 DownloadView.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "DownloadView.h"
#include <QtWidgets>
#include <QtCore>
#include <libethereum/DownloadMan.h>
#include "Grapher.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
DownloadView::DownloadView(QWidget* _p): QWidget(_p)
{
}
void DownloadView::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
if (!m_man || m_man->chain().empty() || !m_man->subCount())
return;
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
ratio = 1 / ratio;
double n = min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n);
QPointF pos(0, 0);
auto const& bg = m_man->blocksGot();
for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i)
{
int s = -2;
if (bg.contains(i))
s = -1;
else
{
unsigned h = 0;
m_man->foreachSub([&](DownloadSub const& sub)
{
if (sub.asked().contains(i))
s = h;
h++;
});
}
unsigned dh = 360 / m_man->subCount();
if (s == -2)
p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black);
else if (s == -1)
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), Qt::black);
else
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), QColor::fromHsv(s * dh, 64, 128));
pos.setX(pos.x() + n);
if (pos.x() >= rect().width() - n)
pos = QPoint(0, pos.y() + n);
}
}

53
alethzero/DownloadView.h

@ -0,0 +1,53 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file DownloadView.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#ifdef Q_MOC_RUN
#define BOOST_MPL_IF_HPP_INCLUDED
#endif
#include <list>
#include <QtWidgets/QWidget>
#ifndef Q_MOC_RUN
#include <libethereum/Client.h>
#endif
namespace dev { namespace eth {
struct MineInfo;
class DownloadMan;
}}
class DownloadView: public QWidget
{
Q_OBJECT
public:
DownloadView(QWidget* _p = nullptr);
void setDownloadMan(dev::eth::DownloadMan const* _man) { m_man = _man; }
protected:
virtual void paintEvent(QPaintEvent*);
private:
dev::eth::DownloadMan const* m_man = nullptr;
};

48
alethzero/Main.ui

@ -132,6 +132,7 @@
</property> </property>
<addaction name="upnp"/> <addaction name="upnp"/>
<addaction name="usePast"/> <addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="net"/> <addaction name="net"/>
<addaction name="connect"/> <addaction name="connect"/>
</widget> </widget>
@ -1432,6 +1433,39 @@ font-size: 14pt</string>
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_12">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Blockchain Download</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_12">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<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>
<widget class="DownloadView" name="downloadView" native="true"/>
</item>
</layout>
</widget>
</widget>
<action name="quit"> <action name="quit">
<property name="text"> <property name="text">
<string>&amp;Quit</string> <string>&amp;Quit</string>
@ -1698,6 +1732,14 @@ font-size: 14pt</string>
<string>Reserved Debug 1</string> <string>Reserved Debug 1</string>
</property> </property>
</action> </action>
<action name="localNetworking">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Local Addresses</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>
@ -1712,6 +1754,12 @@ font-size: 14pt</string>
<header>MiningView.h</header> <header>MiningView.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>DownloadView</class>
<extends>QWidget</extends>
<header>DownloadView.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>destination</tabstop> <tabstop>destination</tabstop>

258
alethzero/MainWin.cpp

@ -30,6 +30,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Dagger.h> #include <libethcore/Dagger.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
@ -38,50 +39,16 @@
#include <libethereum/ExtVM.h> #include <libethereum/ExtVM.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include <libethereum/DownloadMan.h>
#include "DownloadView.h"
#include "MiningView.h" #include "MiningView.h"
#include "BuildInfo.h" #include "BuildInfo.h"
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
using namespace dev;
// types using namespace dev::p2p;
using dev::bytes; using namespace dev::eth;
using dev::bytesConstRef;
using dev::h160;
using dev::h256;
using dev::u160;
using dev::u256;
using dev::Address;
using dev::eth::BlockInfo;
using dev::eth::Client;
using dev::eth::Instruction;
using dev::KeyPair;
using dev::eth::NodeMode;
using dev::eth::BlockChain;
using dev::p2p::PeerInfo;
using dev::RLP;
using dev::Secret;
using dev::eth::Transaction;
using dev::eth::Executive;
// functions
using dev::toHex;
using dev::fromHex;
using dev::left160;
using dev::right160;
using dev::simpleDebugOut;
using dev::toLog2;
using dev::toString;
using dev::operator<<;
using dev::eth::units;
using dev::eth::sha3;
using dev::eth::compileLLL;
using dev::eth::disassemble;
using dev::eth::formatBalance;
// vars
using dev::g_logPost;
using dev::g_logVerbosity;
static void initUnits(QComboBox* _b) static void initUnits(QComboBox* _b)
{ {
@ -114,7 +81,6 @@ static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
return QString(); return QString();
} }
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
@ -133,26 +99,10 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s)); // ui->log->addItem(QString::fromStdString(s));
}; };
#if 0&&ETH_DEBUG #if ETH_DEBUG
m_servers.append("192.168.0.10:30301"); m_servers.append("localhost:30300");
#else
int pocnumber = QString(dev::Version).section('.', 1, 1).toInt();
if (pocnumber == 5)
m_servers.push_back("54.72.69.180:30303");
else if (pocnumber == 6)
m_servers.push_back("54.76.56.74:30303");
else
{
connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r)
{
m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts);
});
QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc" + QString::number(pocnumber) + ".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));
}
#endif #endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
cerr << "State root: " << BlockChain::genesis().stateRoot << endl; cerr << "State root: " << BlockChain::genesis().stateRoot << endl;
cerr << "Block Hash: " << sha3(BlockChain::createGenesisBlock()) << endl; cerr << "Block Hash: " << sha3(BlockChain::createGenesisBlock()) << endl;
@ -177,12 +127,12 @@ Main::Main(QWidget *parent) :
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_client.reset(new Client("AlethZero")); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}));
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_ethereum = new QEthereum(this, client(), owned()); m_ethereum = new QEthereum(this, ethereum(), owned());
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
@ -226,6 +176,11 @@ Main::~Main()
writeSettings(); writeSettings();
} }
dev::p2p::NetworkPreferences Main::netPrefs() const
{
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
}
void Main::onKeysChanged() void Main::onKeysChanged()
{ {
installBalancesWatch(); installBalancesWatch();
@ -233,14 +188,14 @@ void Main::onKeysChanged()
unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f) unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f)
{ {
auto ret = client()->installWatch(_tf); auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f; m_handlers[ret] = _f;
return ret; return ret;
} }
unsigned Main::installWatch(dev::h256 _tf, std::function<void()> const& _f) unsigned Main::installWatch(dev::h256 _tf, std::function<void()> const& _f)
{ {
auto ret = client()->installWatch(_tf); auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f; m_handlers[ret] = _f;
return ret; return ret;
} }
@ -255,14 +210,14 @@ void Main::installWatches()
void Main::installNameRegWatch() void Main::installNameRegWatch()
{ {
client()->uninstallWatch(m_nameRegFilter); ethereum()->uninstallWatch(m_nameRegFilter);
m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)client()->stateAt(c_config, 0)), [=](){ onNameRegChange(); }); m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
} }
void Main::installCurrenciesWatch() void Main::installCurrenciesWatch()
{ {
client()->uninstallWatch(m_currenciesFilter); ethereum()->uninstallWatch(m_currenciesFilter);
m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)client()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); }); m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
} }
void Main::installBalancesWatch() void Main::installBalancesWatch()
@ -270,9 +225,9 @@ void Main::installBalancesWatch()
dev::eth::MessageFilter tf; dev::eth::MessageFilter tf;
vector<Address> altCoins; vector<Address> altCoins;
Address coinsAddr = right160(client()->stateAt(c_config, 1)); Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
for (unsigned i = 0; i < client()->stateAt(coinsAddr, 0); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
altCoins.push_back(right160(client()->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
tf.altered(i.address()); tf.altered(i.address());
@ -280,7 +235,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address()); tf.altered(c, (u160)i.address());
} }
client()->uninstallWatch(m_balancesFilter); ethereum()->uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
} }
@ -328,7 +283,7 @@ void Main::onNewPending()
void Main::on_forceMining_triggered() void Main::on_forceMining_triggered()
{ {
client()->setForceMining(ui->forceMining->isChecked()); ethereum()->setForceMining(ui->forceMining->isChecked());
} }
void Main::on_enableOptimizer_triggered() void Main::on_enableOptimizer_triggered()
@ -422,11 +377,11 @@ QString Main::pretty(dev::Address _a) const
{ {
h256 n; h256 n;
if (h160 nameReg = (u160)client()->stateAt(c_config, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
n = client()->stateAt(nameReg, (u160)(_a)); n = ethereum()->stateAt(nameReg, (u160)(_a));
if (!n) if (!n)
n = client()->stateAt(m_nameReg, (u160)(_a)); n = ethereum()->stateAt(m_nameReg, (u160)(_a));
return fromRaw(n); return fromRaw(n);
} }
@ -452,11 +407,11 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size()); memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size()) if (_a.size())
{ {
if (h160 nameReg = (u160)client()->stateAt(c_config, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = client()->stateAt(nameReg, n)) if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a); return right160(a);
if (h256 a = client()->stateAt(m_nameReg, n)) if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a); return right160(a);
} }
if (_a.size() == 40) if (_a.size() == 40)
@ -484,11 +439,11 @@ QString Main::lookup(QString const& _a) const
*/ */
h256 ret; h256 ret;
if (h160 dnsReg = (u160)client()->stateAt(c_config, 4, 0)) if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
ret = client()->stateAt(dnsReg, n); ret = ethereum()->stateAt(dnsReg, n);
/* if (!ret) /* if (!ret)
if (h160 nameReg = (u160)m_client->stateAt(c_config, 0, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0))
ret = m_client->stateAt(nameReg, n2); ret = ethereum()->stateAt(nameReg, n2);
*/ */
if (ret && !((u256)ret >> 32)) if (ret && !((u256)ret >> 32))
return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]); return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]);
@ -506,7 +461,7 @@ void Main::on_about_triggered()
void Main::on_paranoia_triggered() void Main::on_paranoia_triggered()
{ {
client()->setParanoia(ui->paranoia->isChecked()); ethereum()->setParanoia(ui->paranoia->isChecked());
} }
void Main::writeSettings() void Main::writeSettings()
@ -525,6 +480,7 @@ void Main::writeSettings()
s.setValue("upnp", ui->upnp->isChecked()); s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text()); s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked()); s.setValue("usePast", ui->usePast->isChecked());
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("showAll", ui->showAll->isChecked()); s.setValue("showAll", ui->showAll->isChecked());
@ -537,7 +493,7 @@ void Main::writeSettings()
s.setValue("privateChain", m_privateChain); s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value()); s.setValue("verbosity", ui->verbosity->value());
bytes d = client()->savePeers(); bytes d = m_webThree->savePeers();
if (d.size()) if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size()); m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers); s.setValue("peers", m_peers);
@ -569,11 +525,12 @@ void Main::readSettings(bool _skipGeometry)
m_myKeys.append(KeyPair(k)); m_myKeys.append(KeyPair(k));
} }
} }
client()->setAddress(m_myKeys.back().address()); ethereum()->setAddress(m_myKeys.back().address());
m_peers = s.value("peers").toByteArray(); m_peers = s.value("peers").toByteArray();
ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString()); ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool()); ui->usePast->setChecked(s.value("usePast", true).toBool());
ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forceMining->setChecked(s.value("forceMining", false).toBool()); ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered(); on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool()); ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -665,17 +622,17 @@ void Main::on_nameReg_textChanged()
void Main::on_preview_triggered() void Main::on_preview_triggered()
{ {
client()->setDefault(ui->preview->isChecked() ? 0 : -1); ethereum()->setDefault(ui->preview->isChecked() ? 0 : -1);
refreshAll(); refreshAll();
} }
void Main::refreshMining() void Main::refreshMining()
{ {
dev::eth::MineProgress p = client()->miningProgress(); dev::eth::MineProgress p = ethereum()->miningProgress();
ui->mineStatus->setText(client()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
if (!ui->miningView->isVisible()) if (!ui->miningView->isVisible())
return; return;
list<dev::eth::MineInfo> l = client()->miningHistory(); list<dev::eth::MineInfo> l = ethereum()->miningHistory();
static unsigned lh = 0; static unsigned lh = 0;
if (p.hashes < lh) if (p.hashes < lh)
ui->miningView->resetStats(); ui->miningView->resetStats();
@ -694,12 +651,12 @@ void Main::refreshBalances()
ui->ourAccounts->clear(); ui->ourAccounts->clear();
u256 totalBalance = 0; u256 totalBalance = 0;
map<Address, tuple<QString, u256, u256>> altCoins; map<Address, tuple<QString, u256, u256>> altCoins;
Address coinsAddr = right160(client()->stateAt(c_config, 1)); Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
for (unsigned i = 0; i < client()->stateAt(coinsAddr, 0); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
{ {
auto n = client()->stateAt(coinsAddr, i + 1); auto n = ethereum()->stateAt(coinsAddr, i + 1);
auto addr = right160(client()->stateAt(coinsAddr, n)); auto addr = right160(ethereum()->stateAt(coinsAddr, n));
auto denom = client()->stateAt(coinsAddr, sha3(h256(n).asBytes())); auto denom = ethereum()->stateAt(coinsAddr, sha3(h256(n).asBytes()));
if (denom == 0) if (denom == 0)
denom = 1; denom = 1;
// cdebug << n << addr << denom << sha3(h256(n).asBytes()); // cdebug << n << addr << denom << sha3(h256(n).asBytes());
@ -707,13 +664,13 @@ void Main::refreshBalances()
} }
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
u256 b = client()->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.address());
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)client()->countAt(i.address())), ui->ourAccounts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
totalBalance += b; totalBalance += b;
for (auto& c: altCoins) for (auto& c: altCoins)
get<1>(c.second) += (u256)client()->stateAt(c.first, (u160)i.address()); get<1>(c.second) += (u256)ethereum()->stateAt(c.first, (u160)i.address());
} }
QString b; QString b;
@ -729,12 +686,12 @@ void Main::refreshBalances()
void Main::refreshNetwork() void Main::refreshNetwork()
{ {
auto ps = client()->peers(); auto ps = web3()->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear(); ui->peers->clear();
for (PeerInfo const& i: ps) for (PeerInfo const& i: ps)
ui->peers->addItem(QString("%3 ms - %1:%2 - %4").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()).arg(i.clientVersion.c_str())); ui->peers->addItem(QString("%3 ms - %1:%2 - %4 %5").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()).arg(i.clientVersion.c_str()).arg(QString::fromStdString(toString(i.caps))));
} }
void Main::refreshAll() void Main::refreshAll()
@ -751,7 +708,7 @@ void Main::refreshPending()
{ {
cwatch << "refreshPending()"; cwatch << "refreshPending()";
ui->transactionQueue->clear(); ui->transactionQueue->clear();
for (Transaction const& t: client()->pending()) for (Transaction const& t: ethereum()->pending())
{ {
QString s = t.receiveAddress ? QString s = t.receiveAddress ?
QString("%2 %5> %3: %1 [%4]") QString("%2 %5> %3: %1 [%4]")
@ -759,7 +716,7 @@ void Main::refreshPending()
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
.arg(render(t.receiveAddress)) .arg(render(t.receiveAddress))
.arg((unsigned)t.nonce) .arg((unsigned)t.nonce)
.arg(client()->codeAt(t.receiveAddress).size() ? '*' : '-') : .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString("%2 +> %3: %1 [%4]") QString("%2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str()) .arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
@ -775,16 +732,16 @@ void Main::refreshAccounts()
ui->accounts->clear(); ui->accounts->clear();
ui->contracts->clear(); ui->contracts->clear();
for (auto n = 0; n < 2; ++n) for (auto n = 0; n < 2; ++n)
for (auto i: client()->addresses()) for (auto i: ethereum()->addresses())
{ {
auto r = render(i); auto r = render(i);
if (r.contains('(') == !n) if (r.contains('(') == !n)
{ {
if (n == 0 || ui->showAllAccounts->isChecked()) if (n == 0 || ui->showAllAccounts->isChecked())
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(client()->balanceAt(i)).c_str()).arg(r).arg((unsigned)client()->countAt(i)), ui->accounts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(r).arg((unsigned)ethereum()->countAt(i)), ui->accounts))
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
if (client()->codeAt(i).size()) if (ethereum()->codeAt(i).size())
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(client()->balanceAt(i)).c_str()).arg(r).arg((unsigned)client()->countAt(i)), ui->contracts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(r).arg((unsigned)ethereum()->countAt(i)), ui->contracts))
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
} }
} }
@ -794,7 +751,7 @@ void Main::refreshDestination()
{ {
cwatch << "refreshDestination()"; cwatch << "refreshDestination()";
QString s; QString s;
for (auto i: client()->addresses()) for (auto i: ethereum()->addresses())
if ((s = pretty(i)).size()) if ((s = pretty(i)).size())
// A namereg address // A namereg address
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1) if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
@ -807,8 +764,8 @@ void Main::refreshDestination()
void Main::refreshBlockCount() void Main::refreshBlockCount()
{ {
cwatch << "refreshBlockCount()"; cwatch << "refreshBlockCount()";
auto d = client()->blockChain().details(); auto d = ethereum()->blockChain().details();
auto diff = BlockInfo(client()->blockChain().block()).difficulty; auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); ui->blockCount->setText(QString("%6 #%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
} }
@ -839,7 +796,7 @@ static bool transactionMatch(string const& _f, Transaction const& _t)
void Main::on_turboMining_triggered() void Main::on_turboMining_triggered()
{ {
client()->setTurboMining(ui->turboMining->isChecked()); ethereum()->setTurboMining(ui->turboMining->isChecked());
} }
void Main::refreshBlockChain() void Main::refreshBlockChain()
@ -850,7 +807,7 @@ void Main::refreshBlockChain()
ui->blocks->clear(); ui->blocks->clear();
string filter = ui->blockChainFilter->text().toLower().toStdString(); string filter = ui->blockChainFilter->text().toLower().toStdString();
auto const& bc = client()->blockChain(); auto const& bc = ethereum()->blockChain();
unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10; unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10;
for (auto h = bc.currentHash(); h != bc.genesisHash() && bc.details(h) && i; h = bc.details(h).parent, --i) for (auto h = bc.currentHash(); h != bc.genesisHash() && bc.details(h) && i; h = bc.details(h).parent, --i)
{ {
@ -877,7 +834,7 @@ void Main::refreshBlockChain()
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
.arg(render(t.receiveAddress)) .arg(render(t.receiveAddress))
.arg((unsigned)t.nonce) .arg((unsigned)t.nonce)
.arg(client()->codeAt(t.receiveAddress).size() ? '*' : '-') : .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]") QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str()) .arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
@ -926,6 +883,9 @@ void Main::timerEvent(QTimerEvent*)
if (interval / 100 % 2 == 0) if (interval / 100 % 2 == 0)
refreshMining(); refreshMining();
if (interval / 100 % 2 == 0 && m_webThree->ethereum()->isSyncing())
ui->downloadView->update();
if (m_logChanged) if (m_logChanged)
{ {
m_logLock.lock(); m_logLock.lock();
@ -948,7 +908,7 @@ void Main::timerEvent(QTimerEvent*)
m_ethereum->poll(); m_ethereum->poll();
for (auto const& i: m_handlers) for (auto const& i: m_handlers)
if (client()->checkWatch(i.first)) if (ethereum()->checkWatch(i.first))
i.second(); i.second();
} }
@ -1019,9 +979,9 @@ void Main::on_transactionQueue_currentItemChanged()
stringstream s; stringstream s;
int i = ui->transactionQueue->currentRow(); int i = ui->transactionQueue->currentRow();
if (i >= 0 && i < (int)client()->pending().size()) if (i >= 0 && i < (int)ethereum()->pending().size())
{ {
Transaction tx(client()->pending()[i]); Transaction tx(ethereum()->pending()[i]);
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce)); h256 th = sha3(rlpList(ss, tx.nonce));
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
@ -1049,7 +1009,7 @@ void Main::on_transactionQueue_currentItemChanged()
// s << "Pre: " << fs.rootHash() << "<br/>"; // s << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>"; // s << "Post: <b>" << ts.rootHash() << "</b>";
s << renderDiff(client()->diff(i, 0)); s << renderDiff(ethereum()->diff(i, 0));
} }
ui->pendingInfo->setHtml(QString::fromStdString(s.str())); ui->pendingInfo->setHtml(QString::fromStdString(s.str()));
@ -1076,7 +1036,7 @@ void Main::on_inject_triggered()
{ {
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex"); QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
bytes b = fromHex(s.toStdString()); bytes b = fromHex(s.toStdString());
client()->inject(&b); ethereum()->inject(&b);
} }
void Main::on_blocks_currentItemChanged() void Main::on_blocks_currentItemChanged()
@ -1090,8 +1050,8 @@ void Main::on_blocks_currentItemChanged()
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32); assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer); auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
auto details = client()->blockChain().details(h); auto details = ethereum()->blockChain().details(h);
auto blockData = client()->blockChain().block(h); auto blockData = ethereum()->blockChain().block(h);
auto block = RLP(blockData); auto block = RLP(blockData);
BlockInfo info(blockData); BlockInfo info(blockData);
@ -1115,7 +1075,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Bloom: <b>" << details.bloom << "</b>"; s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>"; s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>"; s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
s << "<br/>Pre: <b>" << BlockInfo(client()->blockChain().block(info.parentHash)).stateRoot << "</b>"; s << "<br/>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>";
for (auto const& i: block[1]) for (auto const& i: block[1])
s << "<br/>" << sha3(i[0].data()).abridged() << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]"; s << "<br/>" << sha3(i[0].data()).abridged() << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]";
s << "<br/>Post: <b>" << info.stateRoot << "</b>"; s << "<br/>Post: <b>" << info.stateRoot << "</b>";
@ -1151,7 +1111,7 @@ void Main::on_blocks_currentItemChanged()
if (tx.data.size()) if (tx.data.size())
s << dev::memDump(tx.data, 16, true); s << dev::memDump(tx.data, 16, true);
} }
s << renderDiff(client()->diff(txi, h)); s << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true); ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true); ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true); ui->debugDumpStatePre->setEnabled(true);
@ -1173,7 +1133,7 @@ void Main::on_debugCurrent_triggered()
if (!item->data(Qt::UserRole + 1).isNull()) if (!item->data(Qt::UserRole + 1).isNull())
{ {
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = client()->state(txi + 1, h); m_executiveState = ethereum()->state(txi + 1, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState)); m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t = m_executiveState.pending()[txi]; Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi); m_executiveState = m_executiveState.fromPending(txi);
@ -1199,7 +1159,7 @@ void Main::on_debugDumpState_triggered(int _add)
if (f.is_open()) if (f.is_open())
{ {
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
f << client()->state(txi + _add, h) << endl; f << ethereum()->state(txi + _add, h) << endl;
} }
} }
} }
@ -1265,10 +1225,10 @@ void Main::on_contracts_currentItemChanged()
stringstream s; stringstream s;
try try
{ {
auto storage = client()->storageAt(address); auto storage = ethereum()->storageAt(address);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>"; s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(client()->codeAt(address)); s << "<h4>Body Code</h4>" << disassemble(ethereum()->codeAt(address));
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
} }
catch (dev::eth::InvalidTrie) catch (dev::eth::InvalidTrie)
@ -1281,7 +1241,7 @@ void Main::on_contracts_currentItemChanged()
void Main::on_idealPeers_valueChanged() void Main::on_idealPeers_valueChanged()
{ {
client()->setIdealPeerCount(ui->idealPeers->value()); m_webThree->setIdealPeerCount(ui->idealPeers->value());
} }
void Main::on_ourAccounts_doubleClicked() void Main::on_ourAccounts_doubleClicked()
@ -1427,7 +1387,7 @@ void Main::on_data_textChanged()
s = s.mid(1); s = s.mid(1);
} }
ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true)));
if (client()->codeAt(fromString(ui->destination->currentText()), 0).size()) if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size())
{ {
ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1)); ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
@ -1450,9 +1410,9 @@ void Main::on_killBlockchain_triggered()
writeSettings(); writeSettings();
ui->mine->setChecked(false); ui->mine->setChecked(false);
ui->net->setChecked(false); ui->net->setChecked(false);
m_client.reset(); web3()->stopNetwork();
m_client.reset(new Client("AlethZero", Address(), string(), true)); ethereum()->killChain();
m_ethereum->setClient(client()); m_ethereum->setClient(ethereum());
readSettings(true); readSettings(true);
installWatches(); installWatches();
refreshAll(); refreshAll();
@ -1495,7 +1455,7 @@ void Main::updateFee()
bool ok = false; bool ok = false;
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (client()->balanceAt(i.address()) >= totalReq) if (ethereum()->balanceAt(i.address()) >= totalReq)
{ {
ok = true; ok = true;
break; break;
@ -1514,15 +1474,24 @@ void Main::on_net_triggered()
if (ui->clientName->text().size()) if (ui->clientName->text().size())
n += "/" + ui->clientName->text().toStdString(); n += "/" + ui->clientName->text().toStdString();
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM); n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);
client()->setClientVersion(n); web3()->setClientVersion(n);
if (ui->net->isChecked()) if (ui->net->isChecked())
{ {
client()->startNetwork(ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0); // TODO: alter network stuff?
//ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
if (m_peers.size() && ui->usePast->isChecked()) if (m_peers.size() && ui->usePast->isChecked())
client()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size())); web3()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
} }
else else
client()->stopNetwork(); {
ui->downloadView->setDownloadMan(nullptr);
web3()->stopNetwork();
}
} }
void Main::on_connect_triggered() void Main::on_connect_triggered()
@ -1538,7 +1507,7 @@ void Main::on_connect_triggered()
{ {
string host = s.section(":", 0, 0).toStdString(); string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt(); unsigned short port = s.section(":", 1).toInt();
client()->connect(host, port); web3()->connect(host, port);
} }
} }
@ -1552,25 +1521,25 @@ void Main::on_mine_triggered()
{ {
if (ui->mine->isChecked()) if (ui->mine->isChecked())
{ {
client()->setAddress(m_myKeys.last().address()); ethereum()->setAddress(m_myKeys.last().address());
client()->startMining(); ethereum()->startMining();
} }
else else
client()->stopMining(); ethereum()->stopMining();
} }
void Main::on_send_clicked() void Main::on_send_clicked()
{ {
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (client()->balanceAt(i.address(), 0) >= totalReq) if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{ {
debugFinished(); debugFinished();
Secret s = i.secret(); Secret s = i.secret();
if (isCreation()) if (isCreation())
client()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
else else
client()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return; return;
} }
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
@ -1583,10 +1552,10 @@ void Main::on_debug_clicked()
{ {
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (client()->balanceAt(i.address()) >= totalReq) if (ethereum()->balanceAt(i.address()) >= totalReq)
{ {
Secret s = i.secret(); Secret s = i.secret();
m_executiveState = client()->postState(); m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState)); m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t; Transaction t;
t.nonce = m_executiveState.transactionsFrom(dev::toAddress(s)); t.nonce = m_executiveState.transactionsFrom(dev::toAddress(s));
@ -1937,4 +1906,7 @@ void Main::updateDebugger()
#include\ #include\
"moc_MiningView.cpp" "moc_MiningView.cpp"
#include\
"moc_DownloadView.cpp"
#endif #endif

9
alethzero/MainWin.h

@ -31,6 +31,7 @@
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libqethereum/QEthereum.h> #include <libqethereum/QEthereum.h>
#include <libwebthree/WebThree.h>
namespace Ui { namespace Ui {
class Main; class Main;
@ -69,7 +70,9 @@ public:
explicit Main(QWidget *parent = 0); explicit Main(QWidget *parent = 0);
~Main(); ~Main();
dev::eth::Client* client() const { return m_client.get(); } dev::WebThreeDirect* web3() const { return m_webThree.get(); }
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
dev::shh::WhisperHost* whisper() const { return m_webThree->whisper(); }
QList<dev::KeyPair> const& owned() const { return m_myKeys; } QList<dev::KeyPair> const& owned() const { return m_myKeys; }
@ -146,6 +149,8 @@ signals:
void poll(); void poll();
private: private:
dev::p2p::NetworkPreferences netPrefs() const;
QString pretty(dev::Address _a) const; QString pretty(dev::Address _a) const;
QString prettyU256(dev::u256 _n) const; QString prettyU256(dev::u256 _n) const;
@ -200,7 +205,7 @@ private:
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::eth::Client> m_client; std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::map<unsigned, std::function<void()>> m_handlers; std::map<unsigned, std::function<void()>> m_handlers;
unsigned m_nameRegFilter = (unsigned)-1; unsigned m_nameRegFilter = (unsigned)-1;

4
eth/CMakeLists.txt

@ -4,13 +4,13 @@ aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(..)
link_directories(../libethcore) link_directories(../libethcore)
link_directories(../libethereum) link_directories(../libwebthree)
set(EXECUTABLE eth) set(EXECUTABLE eth)
add_executable(${EXECUTABLE} ${SRC_LIST}) add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp) target_link_libraries(${EXECUTABLE} gmp)
if(MINIUPNPC_LS) if(MINIUPNPC_LS)

39
eth/EthStubServer.cpp

@ -25,14 +25,15 @@
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "CommonJS.h" #include "CommonJS.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, Client& _client): EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3):
AbstractEthStubServer(_conn), AbstractEthStubServer(_conn),
m_client(_client) m_web3(_web3)
{ {
} }
@ -59,20 +60,25 @@ Json::Value EthStubServer::procedures()
return ret; return ret;
} }
dev::eth::Client& EthStubServer::ethereum() const
{
return *m_web3.ethereum();
}
std::string EthStubServer::coinbase() std::string EthStubServer::coinbase()
{ {
return toJS(m_client.address()); return toJS(ethereum().address());
} }
std::string EthStubServer::balanceAt(std::string const& _a) std::string EthStubServer::balanceAt(std::string const& _a)
{ {
return toJS(m_client.balanceAt(jsToAddress(_a), 0)); return toJS(ethereum().balanceAt(jsToAddress(_a), 0));
} }
Json::Value EthStubServer::check(Json::Value const& _as) Json::Value EthStubServer::check(Json::Value const& _as)
{ {
// TODO // TODO
// if (m_client.changed()) // if (ethereum().changed())
return _as; return _as;
/* else /* else
{ {
@ -84,7 +90,7 @@ Json::Value EthStubServer::check(Json::Value const& _as)
std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice) std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice)
{ {
Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice)); Address ret = ethereum().transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
return toJS(ret); return toJS(ret);
} }
@ -100,17 +106,17 @@ std::string EthStubServer::gasPrice()
bool EthStubServer::isContractAt(const std::string& _a) bool EthStubServer::isContractAt(const std::string& _a)
{ {
return m_client.codeAt(jsToAddress(_a), 0).size(); return ethereum().codeAt(jsToAddress(_a), 0).size();
} }
bool EthStubServer::isListening() bool EthStubServer::isListening()
{ {
return m_client.haveNetwork(); return m_web3.haveNetwork();
} }
bool EthStubServer::isMining() bool EthStubServer::isMining()
{ {
return m_client.isMining(); return ethereum().isMining();
} }
std::string EthStubServer::key() std::string EthStubServer::key()
@ -130,23 +136,28 @@ Json::Value EthStubServer::keys()
int EthStubServer::peerCount() int EthStubServer::peerCount()
{ {
return m_client.peerCount(); return m_web3.peerCount();
} }
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x) std::string EthStubServer::storageAt(const std::string& _a, const std::string& x)
{ {
return toJS(m_client.stateAt(jsToAddress(_a), jsToU256(x), 0)); return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), 0));
}
std::string EthStubServer::stateAt(const std::string& _a, const std::string& x, const std::string& s)
{
return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), std::atol(s.c_str())));
} }
Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue) Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue)
{ {
m_client.transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice)); ethereum().transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice));
return Json::Value(); return Json::Value();
} }
std::string EthStubServer::txCountAt(const std::string& _a) std::string EthStubServer::txCountAt(const std::string& _a)
{ {
return toJS(m_client.countAt(jsToAddress(_a), 0)); return toJS(ethereum().countAt(jsToAddress(_a), 0));
} }
std::string EthStubServer::secretToAddress(const std::string& _a) std::string EthStubServer::secretToAddress(const std::string& _a)
@ -167,7 +178,7 @@ Json::Value EthStubServer::block(const std::string& _hash)
Json::Value EthStubServer::blockJson(const std::string& _hash) Json::Value EthStubServer::blockJson(const std::string& _hash)
{ {
Json::Value res; Json::Value res;
auto const& bc = m_client.blockChain(); auto const& bc = ethereum().blockChain();
auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block(); auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block();

8
eth/EthStubServer.h

@ -29,12 +29,12 @@
#include "abstractethstubserver.h" #include "abstractethstubserver.h"
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
namespace dev { namespace eth { class Client; } class KeyPair; } namespace dev { class WebThreeDirect; namespace eth { class Client; } class KeyPair; }
class EthStubServer: public AbstractEthStubServer class EthStubServer: public AbstractEthStubServer
{ {
public: public:
EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::eth::Client& _client); EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3);
virtual Json::Value procedures(); virtual Json::Value procedures();
virtual std::string balanceAt(std::string const& _a); virtual std::string balanceAt(std::string const& _a);
@ -49,6 +49,7 @@ public:
virtual Json::Value keys(); virtual Json::Value keys();
virtual int peerCount(); virtual int peerCount();
virtual std::string storageAt(const std::string& a, const std::string& x); virtual std::string storageAt(const std::string& a, const std::string& x);
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& s);
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue); virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue);
virtual std::string txCountAt(const std::string& a); virtual std::string txCountAt(const std::string& a);
virtual std::string secretToAddress(const std::string& a); virtual std::string secretToAddress(const std::string& a);
@ -57,7 +58,8 @@ public:
virtual Json::Value block(const std::string&); virtual Json::Value block(const std::string&);
void setKeys(std::vector<dev::KeyPair> _keys) { m_keys = _keys; } void setKeys(std::vector<dev::KeyPair> _keys) { m_keys = _keys; }
private: private:
dev::eth::Client& m_client; dev::eth::Client& ethereum() const;
dev::WebThreeDirect& m_web3;
std::vector<dev::KeyPair> m_keys; std::vector<dev::KeyPair> m_keys;
Json::Value jsontypeToValue(int); Json::Value jsontypeToValue(int);
Json::Value blockJson(const std::string&); Json::Value blockJson(const std::string&);

7
eth/abstractethstubserver.h

@ -30,6 +30,7 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
this->bindAndAddMethod(new jsonrpc::Procedure("procedures", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::proceduresI); this->bindAndAddMethod(new jsonrpc::Procedure("procedures", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::proceduresI);
this->bindAndAddMethod(new jsonrpc::Procedure("secretToAddress", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::secretToAddressI); this->bindAndAddMethod(new jsonrpc::Procedure("secretToAddress", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::secretToAddressI);
this->bindAndAddMethod(new jsonrpc::Procedure("storageAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::storageAtI); this->bindAndAddMethod(new jsonrpc::Procedure("storageAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::storageAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING,"s",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "aDest",jsonrpc::JSON_STRING,"bData",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING,"xValue",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::transactI); this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "aDest",jsonrpc::JSON_STRING,"bData",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING,"xValue",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("txCountAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::txCountAtI); this->bindAndAddMethod(new jsonrpc::Procedure("txCountAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::txCountAtI);
@ -120,6 +121,11 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
response = this->storageAt(request["a"].asString(), request["x"].asString()); response = this->storageAt(request["a"].asString(), request["x"].asString());
} }
inline virtual void stateAtI(const Json::Value& request, Json::Value& response)
{
response = this->stateAt(request["a"].asString(), request["x"].asString(), request["s"].asString());
}
inline virtual void transactI(const Json::Value& request, Json::Value& response) inline virtual void transactI(const Json::Value& request, Json::Value& response)
{ {
response = this->transact(request["aDest"].asString(), request["bData"].asString(), request["sec"].asString(), request["xGas"].asString(), request["xGasPrice"].asString(), request["xValue"].asString()); response = this->transact(request["aDest"].asString(), request["bData"].asString(), request["sec"].asString(), request["xGas"].asString(), request["xGasPrice"].asString(), request["xValue"].asString());
@ -148,6 +154,7 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
virtual Json::Value procedures() = 0; virtual Json::Value procedures() = 0;
virtual std::string secretToAddress(const std::string& a) = 0; virtual std::string secretToAddress(const std::string& a) = 0;
virtual std::string storageAt(const std::string& a, const std::string& x) = 0; virtual std::string storageAt(const std::string& a, const std::string& x) = 0;
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& b) = 0;
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue) = 0; virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue) = 0;
virtual std::string txCountAt(const std::string& a) = 0; virtual std::string txCountAt(const std::string& a) = 0;

12
eth/eth.js

@ -25,6 +25,7 @@ var spec = [
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 }, { "method": "peerCount", "params": null, "order": [], "returns" : 0 },
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" }, { "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" }, { "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" },
{ "method": "stateAt", "params": { "a": "", "x": "", "s": "" }, "order": ["a", "x", "s"], "returns" : "" },
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" }, { "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" },
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false }, { "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false },
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" }, { "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" },
@ -70,9 +71,14 @@ window.eth = (function ethScope() {
var m = s.method; var m = s.method;
var am = "get" + m.slice(0, 1).toUpperCase() + m.slice(1); var am = "get" + m.slice(0, 1).toUpperCase() + m.slice(1);
var getParams = function(a) { var getParams = function(a) {
var p = s.params ? {} : null var p = s.params ? {} : null;
if (m == "stateAt")
if (a.length == 2)
a[2] = "0";
else
a[2] = String(a[2]);
for (j in s.order) for (j in s.order)
p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j] p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j];
return p return p
}; };
if (m == "create" || m == "transact") if (m == "create" || m == "transact")
@ -101,7 +107,7 @@ window.eth = (function ethScope() {
for (var c in changed) for (var c in changed)
m_watching[changed[c]]() m_watching[changed[c]]()
var that = this; var that = this;
setTimeout(function() { that.check() }, 5000) setTimeout(function() { that.check() }, 12000)
} }
ret.watch = function(a, fx, f) { ret.watch = function(a, fx, f) {

147
eth/main.cpp

@ -33,6 +33,7 @@
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_READLINE #if ETH_READLINE
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
@ -43,6 +44,7 @@
#include "BuildInfo.h" #include "BuildInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p;
using namespace dev::eth; using namespace dev::eth;
using namespace boost::algorithm; using namespace boost::algorithm;
using dev::eth::Instruction; using dev::eth::Instruction;
@ -97,6 +99,7 @@ void help()
<< "Usage eth [OPTIONS] <remote-host>" << endl << "Usage eth [OPTIONS] <remote-host>" << endl
<< "Options:" << endl << "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl << " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl << " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl << " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
@ -110,7 +113,8 @@ void help()
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl << " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl << " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
@ -131,17 +135,8 @@ string credits(bool _interactive = false)
if (_interactive) if (_interactive)
{ {
string vs = toString(dev::Version);
vs = vs.substr(vs.find_first_of('.') + 1)[0];
int pocnumber = stoi(vs);
string m_servers;
if (pocnumber == 4)
m_servers = "54.72.31.55";
else
m_servers = "54.72.69.180";
cout << "Type 'netstart 30303' to start networking" << endl; cout << "Type 'netstart 30303' to start networking" << endl;
cout << "Type 'connect " << m_servers << " 30303' to connect" << endl; cout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl;
cout << "Type 'exit' to quit" << endl << endl; cout << "Type 'exit' to quit" << endl << endl;
} }
return cout.str(); return cout.str();
@ -182,10 +177,12 @@ int main(int argc, char** argv)
unsigned peers = 5; unsigned peers = 5;
bool interactive = false; bool interactive = false;
#if ETH_JSONRPC #if ETH_JSONRPC
int jsonrpc = 8080; int jsonrpc = -1;
#endif #endif
string publicIP; string publicIP;
bool bootstrap = false;
bool upnp = true; bool upnp = true;
bool useLocal = false;
bool forceMining = false; bool forceMining = false;
string clientName; string clientName;
@ -231,10 +228,12 @@ int main(int argc, char** argv)
upnp = false; upnp = false;
else else
{ {
cerr << "Invalid UPnP option: " << m << endl; cerr << "Invalid -n/--upnp option: " << m << endl;
return -1; return -1;
} }
} }
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i]; clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@ -254,17 +253,19 @@ int main(int argc, char** argv)
mining = i; mining = i;
else else
{ {
cerr << "Unknown mining option: " << m << endl; cerr << "Unknown -m/--mining option: " << m << endl;
return -1; return -1;
} }
} }
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
else if (arg == "-f" || arg == "--force-mining") else if (arg == "-f" || arg == "--force-mining")
forceMining = true; forceMining = true;
else if (arg == "-i" || arg == "--interactive") else if (arg == "-i" || arg == "--interactive")
interactive = true; interactive = true;
#if ETH_JSONRPC #if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc")) else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc ? jsonrpc : 8080; jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc) else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]); jsonrpc = atoi(argv[++i]);
#endif #endif
@ -296,22 +297,32 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
Client c("Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath);
c.setForceMining(true);
cout << credits(); cout << credits();
c.setForceMining(forceMining); NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3("Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath, false, mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>{}, netPrefs);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
if (c)
{
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
cout << "Address: " << endl << toHex(us.address().asArray()) << endl; cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC #if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer; auto_ptr<EthStubServer> jsonrpcServer;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us}); jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
@ -349,34 +360,34 @@ int main(int argc, char** argv)
iss >> cmd; iss >> cmd;
if (cmd == "netstart") if (cmd == "netstart")
{ {
unsigned port; iss >> netPrefs.listenPort;
iss >> port; web3.setNetworkPreferences(netPrefs);
c.startNetwork((short)port); web3.startNetwork();
} }
else if (cmd == "connect") else if (cmd == "connect")
{ {
string addr; string addr;
unsigned port; unsigned port;
iss >> addr >> port; iss >> addr >> port;
c.connect(addr, (short)port); web3.connect(addr, (short)port);
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {
c.stopNetwork(); web3.stopNetwork();
} }
else if (cmd == "minestart") else if (c && cmd == "minestart")
{ {
c.startMining(); c->startMining();
} }
else if (cmd == "minestop") else if (c && cmd == "minestop")
{ {
c.stopMining(); c->stopMining();
} }
else if (cmd == "mineforce") else if (c && cmd == "mineforce")
{ {
string enable; string enable;
iss >> enable; iss >> enable;
c.setForceMining(isTrue(enable)); c->setForceMining(isTrue(enable));
} }
else if (cmd == "verbosity") else if (cmd == "verbosity")
{ {
@ -395,7 +406,7 @@ int main(int argc, char** argv)
{ {
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = 8080; jsonrpc = 8080;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us}); jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
@ -416,24 +427,24 @@ int main(int argc, char** argv)
{ {
cout << "Secret Key: " << toHex(us.secret().asArray()) << endl; cout << "Secret Key: " << toHex(us.secret().asArray()) << endl;
} }
else if (cmd == "block") else if (c && cmd == "block")
{ {
cout << "Current block: " << c.blockChain().details().number << endl; cout << "Current block: " <<c->blockChain().details().number << endl;
} }
else if (cmd == "peers") else if (cmd == "peers")
{ {
for (auto it: c.peers()) for (auto it: web3.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", " cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms" << std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl; << endl;
} }
else if (cmd == "balance") else if (c && cmd == "balance")
{ {
cout << "Current balance: " << formatBalance(c.balanceAt(us.address())) << " = " << c.balanceAt(us.address()) << " wei" << endl; cout << "Current balance: " << formatBalance( c->balanceAt(us.address())) << " = " <<c->balanceAt(us.address()) << " wei" << endl;
} }
else if (cmd == "transact") else if (c && cmd == "transact")
{ {
auto const& bc = c.blockChain(); auto const& bc =c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
@ -478,35 +489,35 @@ int main(int argc, char** argv)
{ {
Secret secret = h256(fromHex(sechex)); Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(hexAddr)); Address dest = h160(fromHex(hexAddr));
c.transact(secret, amount, dest, data, gas, gasPrice); c->transact(secret, amount, dest, data, gas, gasPrice);
} }
} }
else else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
} }
else if (cmd == "listContracts") else if (c && cmd == "listContracts")
{ {
auto acs = c.addresses(); auto acs =c->addresses();
string ss; string ss;
for (auto const& i: acs) for (auto const& i: acs)
if (c.codeAt(i, 0).size()) if ( c->codeAt(i, 0).size())
{ {
ss = toString(i) + " : " + toString(c.balanceAt(i)) + " [" + toString((unsigned)c.countAt(i)) + "]"; ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl; cout << ss << endl;
} }
} }
else if (cmd == "listAccounts") else if (c && cmd == "listAccounts")
{ {
auto acs = c.addresses(); auto acs =c->addresses();
string ss; string ss;
for (auto const& i: acs) for (auto const& i: acs)
if (c.codeAt(i, 0).empty()) if ( c->codeAt(i, 0).empty())
{ {
ss = toString(i) + " : " + toString(c.balanceAt(i)) + " [" + toString((unsigned)c.countAt(i)) + "]"; ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl; cout << ss << endl;
} }
} }
else if (cmd == "send") else if (c && cmd == "send")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
@ -522,21 +533,21 @@ int main(int argc, char** argv)
} }
else else
{ {
auto const& bc = c.blockChain(); auto const& bc =c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
u256 minGas = (u256)Client::txGas(0, 0); u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(hexAddr)); Address dest = h160(fromHex(hexAddr));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); c->transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
} }
} }
else else
cwarn << "Require parameters: send ADDRESS AMOUNT"; cwarn << "Require parameters: send ADDRESS AMOUNT";
} }
else if (cmd == "contract") else if (c && cmd == "contract")
{ {
auto const& bc = c.blockChain(); auto const& bc =c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
@ -573,12 +584,12 @@ int main(int argc, char** argv)
else if (gas < minGas) else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas; cwarn << "Minimum gas amount is" << minGas;
else else
c.transact(us.secret(), endowment, init, gas, gasPrice); c->transact(us.secret(), endowment, init, gas, gasPrice);
} }
else else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
} }
else if (cmd == "dumptrace") else if (c && cmd == "dumptrace")
{ {
unsigned block; unsigned block;
unsigned index; unsigned index;
@ -588,7 +599,7 @@ int main(int argc, char** argv)
ofstream f; ofstream f;
f.open(filename); f.open(filename);
dev::eth::State state = c.state(index + 1, c.blockChain().numberHash(block)); dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size()) if (index < state.pending().size())
{ {
Executive e(state); Executive e(state);
@ -633,7 +644,7 @@ int main(int argc, char** argv)
e.finalize(oof); e.finalize(oof);
} }
} }
else if (cmd == "inspect") else if (c && cmd == "inspect")
{ {
string rechex; string rechex;
iss >> rechex; iss >> rechex;
@ -647,10 +658,10 @@ int main(int argc, char** argv)
try try
{ {
auto storage = c.storageAt(h, 0); auto storage =c->storageAt(h, 0);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.codeAt(h, 0)) << endl; s << endl << disassemble( c->codeAt(h, 0)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm"; string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs; ofstream ofs;
@ -735,19 +746,21 @@ int main(int argc, char** argv)
jsonrpcServer->StopListening(); jsonrpcServer->StopListening();
#endif #endif
} }
else else if (c)
{ {
unsigned n = c.blockChain().details().number; unsigned n =c->blockChain().details().number;
if (mining) if (mining)
c.startMining(); c->startMining();
while (true) while (true)
{ {
if (c.blockChain().details().number - n == mining) if ( c->isMining() &&c->blockChain().details().number - n == mining)
c.stopMining(); c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100)); this_thread::sleep_for(chrono::milliseconds(100));
} }
} }
else
while (true)
this_thread::sleep_for(chrono::milliseconds(1000));
return 0; return 0;
} }

310
exp/main.cpp

@ -19,290 +19,59 @@
* @date 2014 * @date 2014
* Ethereum client. * Ethereum client.
*/ */
#if 0 #include <functional>
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_utree.hpp>
#endif
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>
#include <libwhisper/WhisperPeer.h> #include <libwhisper/WhisperPeer.h>
#if 0
#include <libevm/VM.h>
#include "BuildInfo.h"
#endif
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
#if 0
#if 0
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
namespace sp = boost::spirit;
int main()
class ASTSymbol: public string
{
public:
ASTSymbol() {}
};
enum class ASTType
{
Symbol,
IntegerLiteral,
StringLiteral,
Call,
Return,
Operator,
Compound
};
class ASTNode: public vector<ASTNode>
{
public:
ASTNode() {}
ASTNode(ASTSymbol const& _s): m_type(ASTType::Symbol), m_s(_s) {}
ASTNode(string const& _s): m_type(ASTType::StringLiteral), m_s(_s) {}
ASTNode(bigint const& _i): m_type(ASTType::IntegerLiteral), m_i(_i) {}
ASTNode(ASTType _t): m_type(_t) {}
ASTNode& operator=(ASTSymbol const& _s) { m_type = ASTType::Symbol; m_s = _s; return *this; }
ASTNode& operator=(string const& _s) { m_type = ASTType::StringLiteral; m_s = _s; return *this; }
ASTNode& operator=(bigint const& _i) { m_type = ASTType::IntegerLiteral; m_i = _i; return *this; }
ASTNode& operator=(ASTType const& _s) { m_type = _s; return *this; }
void debugOut(ostream& _out) const;
private:
ASTType m_type;
string m_s;
bigint m_i;
};
void parseTree(string const& _s, ASTNode& o_out)
{
using qi::standard::space;
using qi::standard::space_type;
typedef string::const_iterator it;
/* static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;*/
qi::rule<it, space_type, ASTNode()> element;
qi::rule<it, space_type, ASTNode()> call;
qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
qi::rule<it, ASTSymbol()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
/* qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether];
qi::rule<it, space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
qi::rule<it, space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> seq = '{' > *element > '}';
qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
qi::rule<it, space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> calldataload = qi::lit("$") > element;
qi::rule<it, space_type, sp::utree::list_type()> list = '(' > *element > ')';
qi::rule<it, space_type, sp::utree()> extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()];*/
qi::rule<it, space_type, ASTNode()> value = call[qi::_val = ASTType::Call] | str[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, ASTNode()> compound = '{' > *element > '}';
call = '(' > *value > ')'; //symbol > '(' > !(value > *(',' > value)) > ')';
element = compound[qi::_val = ASTType::Compound] | value[qi::_val = qi::_1];
auto ret = _s.cbegin();
qi::phrase_parse(ret, _s.cend(), element, space, qi::skip_flag::dont_postskip, o_out);
for (auto i = ret; i != _s.cend(); ++i)
if (!isspace(*i))
throw std::exception();
}
void ASTNode::debugOut(ostream& _out) const
{
switch (m_type)
{
case ASTType::StringLiteral:
_out << "\"" << m_s << "\"";
break;
case ASTType::Symbol:
_out << m_s;
break;
case ASTType::Compound:
{
unsigned n = 0;
_out << "{";
for (auto const& i: *this)
{
i.debugOut(_out);
_out << ";";
++n;
}
_out << "}";
break;
}
case ASTType::Call:
{
unsigned n = 0;
for (auto const& i: *this)
{
i.debugOut(_out);
if (n == 0)
_out << "(";
else if (n < size() - 1)
_out << ",";
if (n == size() - 1)
_out << ")";
++n;
}
break;
}
default:
_out << "nil";
}
}
int main(int, char**)
{ {
ASTNode out; DownloadMan man;
parseTree("{x}", out); DownloadSub s0(man);
out.debugOut(cout); DownloadSub s1(man);
cout << endl; DownloadSub s2(man);
man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)}));
cnote << s0.nextFetch(2);
cnote << s1.nextFetch(2);
cnote << s2.nextFetch(2);
s0.noteBlock(u256(0));
s0.doneFetch();
cnote << s0.nextFetch(2);
s1.noteBlock(u256(2));
s1.noteBlock(u256(3));
s1.doneFetch();
cnote << s1.nextFetch(2);
s0.doneFetch();
cnote << s0.nextFetch(2);
/* RangeMask<unsigned> m(0, 100);
cnote << m;
m += UnsignedRange(3, 10);
cnote << m;
m += UnsignedRange(11, 16);
cnote << m;
m += UnsignedRange(10, 11);
cnote << m;
cnote << ~m;
cnote << (~m).lowest(10);
for (auto i: (~m).lowest(10))
cnote << i;*/
return 0; return 0;
} }
#endif
void killBigints(sp::utree const& _this) /*
{
switch (_this.which())
{
case sp::utree_type::list_type: for (auto const& i: _this) killBigints(i); break;
case sp::utree_type::any_type: delete _this.get<bigint*>(); break;
default:;
}
}
void debugOutAST(ostream& _out, sp::utree const& _this)
{
switch (_this.which())
{
case sp::utree_type::list_type:
switch (_this.tag())
{
case 0: { int n = 0; for (auto const& i: _this) { debugOutAST(_out, i); if (n++) _out << ", "; } break; }
case 1: _out << "@ "; debugOutAST(_out, _this.front()); break;
case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break;
case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break;
case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break;
case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break;
case 6: _out << "$ "; debugOutAST(_out, _this.front()); break;
default:
{ _out << _this.tag() << ": "; int n = 0; for (auto const& i: _this) { debugOutAST(_out, i); if (n++) _out << ", "; } break; }
}
break;
case sp::utree_type::int_type: _out << _this.get<int>(); break;
case sp::utree_type::string_type: _out << "\"" << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>() << "\""; break;
case sp::utree_type::symbol_type: _out << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); break;
case sp::utree_type::any_type: _out << *_this.get<bigint*>(); break;
default: _out << "nil";
}
}
namespace dev {
namespace eth {
namespace parseTreeLLL_ {
template<unsigned N>
struct tagNode
{
void operator()(sp::utree& n, qi::rule<string::const_iterator, qi::ascii::space_type, sp::utree()>::context_type& c) const
{
(boost::fusion::at_c<0>(c.attributes) = n).tag(N);
}
};
}}}
void parseTree(string const& _s, sp::utree& o_out)
{
using qi::standard::space;
using qi::standard::space_type;
using dev::eth::parseTreeLLL_::tagNode;
typedef sp::basic_string<std::string, sp::utree_type::symbol_type> symbol_type;
typedef string::const_iterator it;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
#if 0
qi::rule<it, space_type, sp::utree()> element;
qi::rule<it, space_type, sp::utree()> statement;
qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether];
qi::rule<it, space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
qi::rule<it, space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> compound = '{' > *statement > '}';
/* qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
qi::rule<it, space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> calldataload = qi::lit("$") > element;*/
// qi::rule<it, space_type, sp::utree::list_type()> args = '(' > (element % ',') > ')';
qi::rule<it, space_type, sp::utree::list_type()> expression;
qi::rule<it, space_type, sp::utree()> group = '(' >> expression[qi::_val = qi::_1] >> ')';
qi::rule<it, space_type, sp::utree()> factor = atom | group;
qi::rule<it, space_type, sp::utree()> mul = '*' >> factor;
qi::rule<it, space_type, sp::utree()> div = '/' >> factor;
qi::rule<it, space_type, sp::utree()> op = mul[tagNode<10>()] | div[tagNode<11>()];
qi::rule<it, space_type, sp::utree::list_type()> term = factor >> !op;
expression = term >> !(('+' >> term) | ('-' >> term));
// qi::rule<it, space_type, sp::utree()> extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | calldataload[tagNode<6>()];
statement = compound[tagNode<5>()] | (element > ';')[qi::_val = qi::_1];
element %= expression;// | extra;
#endif
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, sp::utree()> intnode = integer[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))];
qi::rule<it, space_type, sp::utree()> funcname = symbol;
qi::rule<it, space_type, sp::utree()> statement;
qi::rule<it, space_type, sp::utree::list_type()> call = funcname > '(' > funcname > ')';
statement = call | intnode | symbol;
auto ret = _s.cbegin();
qi::phrase_parse(ret, _s.cend(), statement, space, qi::skip_flag::dont_postskip, o_out);
for (auto i = ret; i != _s.cend(); ++i)
if (!isspace(*i))
throw std::exception();
}
#endif
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
#if 0
sp::utree out;
parseTree("x(2)", out);
debugOutAST(cout, out);
killBigints(out);
cout << endl;
#endif
g_logVerbosity = 20; g_logVerbosity = 20;
short listenPort = 30303; short listenPort = 30303;
@ -322,24 +91,25 @@ int main(int argc, char** argv)
remoteHost = argv[i]; remoteHost = argv[i];
} }
Host ph("Test", listenPort, "", false, true); Host ph("Test", NetworkPreferences(listenPort, "", false, true));
ph.registerCapability(new WhisperHost()); ph.registerCapability(new WhisperHost());
auto wh = ph.cap<WhisperHost>(); auto wh = ph.cap<WhisperHost>();
ph.start();
if (!remoteHost.empty()) if (!remoteHost.empty())
ph.connect(remoteHost, remotePort); ph.connect(remoteHost, remotePort);
/// Only interested in the packet if the lowest bit is 1 /// Only interested in the packet if the lowest bit is 1
auto w = wh->installWatch(MessageFilter(std::vector<std::pair<bytes, bytes> >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}}))); auto w = wh->installWatch(MessageFilter(std::vector<std::pair<bytes, bytes> >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}})));
for (int i = 0; ; ++i) for (int i = 0; ; ++i)
{ {
this_thread::sleep_for(chrono::milliseconds(1000));
ph.process();
wh->sendRaw(h256(u256(i * i)).asBytes(), h256(u256(i)).asBytes(), 1000); wh->sendRaw(h256(u256(i * i)).asBytes(), h256(u256(i)).asBytes(), 1000);
for (auto i: wh->checkWatch(w)) for (auto i: wh->checkWatch(w))
cnote << "New message:" << (u256)h256(wh->message(i).payload); cnote << "New message:" << (u256)h256(wh->message(i).payload);
} }
return 0; return 0;
} }
*/

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.6.8b"; char const* Version = "0.6.9";
} }

178
libdevcore/CommonData.cpp

@ -102,3 +102,181 @@ bytes dev::asNibbles(std::string const& _s)
} }
return ret; return ret;
} }
#if 0
/* Following code is copyright 2012-2014 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details.
*/
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstring>
static const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
{
size_t binsz = *binszp;
const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
// Leading zeros, just count
for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
++zerocount;
for ( ; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i)
{
if (binu[i])
break;
--*binszp;
}
*binszp += zerocount;
return true;
}
static
bool my_dblsha256(void *hash, const void *data, size_t datasz)
{
uint8_t buf[0x20];
return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf));
}
int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
if (!my_dblsha256(buf, bin, binsz - 4))
return -2;
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
return binc[0];
}
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int carry;
size_t i, j, high, zcount = 0;
size_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memset(buf, 0, size);
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < size && !buf[j]; ++j);
if (*b58sz <= zcount + size - j)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
}
#endif

5
libdevcore/CommonData.h

@ -55,6 +55,11 @@ int fromHex(char _i);
/// @example fromHex("41626261") == asBytes("Abba") /// @example fromHex("41626261") == asBytes("Abba")
bytes fromHex(std::string const& _s); bytes fromHex(std::string const& _s);
#if 0
std::string toBase58(bytesConstRef _data);
bytes fromBase58(std::string const& _s);
#endif
/// Converts byte array to a string containing the same (binary) data. Unless /// 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. /// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b) inline std::string asString(bytes const& _b)

20
libdevcore/CommonIO.h

@ -49,15 +49,6 @@ void writeFile(std::string const& _file, bytes const& _data);
/// Nicely renders the given bytes to a string, optionally as HTML. /// Nicely renders the given bytes to a string, optionally as HTML.
std::string memDump(bytes const& _b, unsigned _w = 8, bool _html = false); std::string memDump(bytes const& _b, unsigned _w = 8, bool _html = false);
/// 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. // Stream I/O functions.
// Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface. // Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface.
@ -223,4 +214,15 @@ template <class T, class U> inline std::ostream& operator<<(std::ostream& _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; } template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
// Functions that use streaming stuff.
/// 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();
}
} }

5
libdevcore/RLP.h

@ -160,7 +160,6 @@ public:
explicit operator std::string() const { return toString(); } explicit operator std::string() const { return toString(); }
explicit operator RLPs() const { return toList(); } explicit operator RLPs() const { return toList(); }
explicit operator byte() const { return toInt<byte>(); } explicit operator byte() const { return toInt<byte>(); }
explicit operator unsigned() const { return toInt<unsigned>(); }
explicit operator u256() const { return toInt<u256>(); } explicit operator u256() const { return toInt<u256>(); }
explicit operator bigint() const { return toInt<bigint>(); } explicit operator bigint() const { return toInt<bigint>(); }
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); } template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }
@ -213,8 +212,8 @@ public:
std::pair<T, U> ret; std::pair<T, U> ret;
if (isList()) if (isList())
{ {
ret.first = (*this)[0].operator T(); ret.first = (T)(*this)[0];
ret.second = (*this)[1].operator U(); ret.second = (U)(*this)[1];
} }
return ret; return ret;
} }

22
libdevcore/RangeMask.cpp

@ -0,0 +1,22 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file RangeMask.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "RangeMask.h"

212
libdevcore/RangeMask.h

@ -0,0 +1,212 @@
/*
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 EthereumHost.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <utility>
#include <vector>
#include <iostream>
namespace dev
{
class RLPStream;
using UnsignedRange = std::pair<unsigned, unsigned>;
using UnsignedRanges = std::vector<UnsignedRange>;
template <class T>
class RangeMask
{
template <class U> friend std::ostream& operator<<(std::ostream& _out, RangeMask<U> const& _r);
public:
using Range = std::pair<T, T>;
using Ranges = std::vector<Range>;
RangeMask() {}
RangeMask(T _begin, T _end): m_all(_begin, _end) {}
RangeMask(Range const& _c): m_all(_c) {}
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; }
RangeMask lowest(T _items) const
{
RangeMask ret(m_all);
for (auto i = m_ranges.begin(); i != m_ranges.end() && _items; ++i)
_items -= (ret.m_ranges[i->first] = std::min(i->first + _items, i->second)) - i->first;
return ret;
}
RangeMask operator~() const
{
RangeMask ret(m_all);
T last = m_all.first;
for (auto i: m_ranges)
{
if (i.first != last)
ret.m_ranges[last] = i.first;
last = i.second;
}
if (last != m_all.second)
ret.m_ranges[last] = m_all.second;
return ret;
}
RangeMask& operator+=(RangeMask const& _m)
{
for (auto const& i: _m.m_ranges)
operator+=(i);
return *this;
}
RangeMask& operator+=(UnsignedRange const& _m)
{
for (auto i = _m.first; i < _m.second;)
{
// for each number, we find the element equal or next lower. this, if any, must contain the value.
auto uit = m_ranges.upper_bound(i);
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
if (it == m_ranges.end() || it->second < i)
// lower range is too low to merge.
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// just create a new range
m_ranges[i] = _m.second;
break;
}
else
{
if (uit->first == i)
// move i to end of range
i = uit->second;
else
{
// merge with the next higher range
// move i to end of range
i = m_ranges[i] = uit->second;
i = uit->second;
m_ranges.erase(uit);
}
}
else if (it->second == i)
{
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// merge with the next lower range
m_ranges[it->first] = _m.second;
break;
}
else
{
// merge with both next lower & next higher.
i = m_ranges[it->first] = uit->second;
m_ranges.erase(uit);
}
}
else
i = it->second;
}
return *this;
}
RangeMask& operator+=(T _i)
{
return operator+=(Range(_i, _i + 1));
}
bool contains(T _i) const
{
auto it = m_ranges.upper_bound(_i);
if (it == m_ranges.begin())
return false;
return (--it)->second > _i;
}
bool empty() const
{
return m_ranges.empty();
}
bool full() const
{
return m_ranges.size() == 1 && m_ranges.begin()->first == m_all.first && m_ranges.begin()->second == m_all.second;
}
void clear()
{
m_ranges.clear();
}
std::pair<T, T> const& all() const { return m_all; }
class const_iterator
{
friend class RangeMask;
public:
const_iterator() {}
T operator*() const { return m_value; }
const_iterator& operator++() { if (m_owner) m_value = m_owner->next(m_value); return *this; }
const_iterator operator++(int) { auto ret = *this; if (m_owner) m_value = m_owner->next(m_value); return ret; }
bool operator==(const_iterator const& _i) const { return m_owner == _i.m_owner && m_value == _i.m_value; }
bool operator!=(const_iterator const& _i) const { return !operator==(_i); }
bool operator<(const_iterator const& _i) const { return m_value < _i.m_value; }
private:
const_iterator(RangeMask const& _m, bool _end): m_owner(&_m), m_value(_m.m_ranges.empty() || _end ? _m.m_all.second : _m.m_ranges.begin()->first) {}
RangeMask const* m_owner = nullptr;
T m_value = 0;
};
const_iterator begin() const { return const_iterator(*this, false); }
const_iterator end() const { return const_iterator(*this, true); }
T next(T _t) const
{
_t++;
// find next item in range at least _t
auto uit = m_ranges.upper_bound(_t); // > _t
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
if (it != m_ranges.end() && it->first <= _t && it->second > _t)
return _t;
return uit == m_ranges.end() ? m_all.second : uit->first;
}
private:
UnsignedRange m_all;
std::map<T, T> m_ranges;
};
template <class T> inline std::ostream& operator<<(std::ostream& _out, RangeMask<T> const& _r)
{
_out << _r.m_all.first << "{ ";
for (auto const& i: _r.m_ranges)
_out << "[" << i.first << ", " << i.second << ") ";
_out << "}" << _r.m_all.second;
return _out;
}
}

63
libdevcore/Worker.cpp

@ -0,0 +1,63 @@
/*
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 Worker.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Worker.h"
#include <chrono>
#include <thread>
#include "Log.h"
using namespace std;
using namespace dev;
void Worker::startWorking()
{
cdebug << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
return;
cdebug << "Spawning" << m_name;
m_stop = false;
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
while (!m_stop)
{
this_thread::sleep_for(chrono::milliseconds(30));
doWork();
}
cdebug << "Finishing up worker thread";
doneWorking();
}));
}
void Worker::stopWorking()
{
cdebug << "stopWorking for thread" << m_name;
Guard l(x_work);
if (!m_work)
return;
cdebug << "Stopping" << m_name;
m_stop = true;
m_work->join();
m_work.reset();
cdebug << "Stopped" << m_name;
}

59
libdevcore/Worker.h

@ -0,0 +1,59 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Worker.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <string>
#include <thread>
#include "Guards.h"
namespace dev
{
class Worker
{
protected:
Worker(std::string const& _name = "anon"): m_name(_name) {}
/// Move-constructor.
Worker(Worker&& _m) { std::swap(m_name, _m.m_name); }
/// Move-assignment.
Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; }
virtual ~Worker() { stopWorking(); }
void setName(std::string _n) { if (!isWorking()) m_name = _n; }
void startWorking();
void stopWorking();
bool isWorking() const { Guard l(x_work); return !!m_work; }
virtual void doWork() = 0;
virtual void doneWorking() {}
private:
mutable Mutex x_work; ///< Lock for the network existance.
std::unique_ptr<std::thread> m_work; ///< The network thread.
bool m_stop = false;
std::string m_name;
};
}

3
libdevcrypto/FileSystem.cpp

@ -31,9 +31,8 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth;
std::string dev::eth::getDataDir() std::string dev::getDataDir()
{ {
#ifdef _WIN32 #ifdef _WIN32
char path[1024] = ""; char path[1024] = "";

3
libdevcrypto/FileSystem.h

@ -27,11 +27,8 @@
namespace dev namespace dev
{ {
namespace eth
{
/// @returns the path for user data. /// @returns the path for user data.
std::string getDataDir(); std::string getDataDir();
} }
}

2
libethcore/BlockInfo.h

@ -56,7 +56,7 @@ extern u256 c_genesisDifficulty;
struct BlockInfo struct BlockInfo
{ {
public: public:
h256 hash; ///< SHA3 hash of the entire block! Not serialised (the only member not contained in a block header). h256 hash; ///< SHA3 hash of the block header! Not serialised (the only member not contained in a block header).
h256 parentHash; h256 parentHash;
h256 sha3Uncles; h256 sha3Uncles;
Address coinbaseAddress; Address coinbaseAddress;

2
libethcore/CommonEth.cpp

@ -34,7 +34,7 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 32; const unsigned c_protocolVersion = 33;
const unsigned c_databaseVersion = 1; const unsigned c_databaseVersion = 1;
static const vector<pair<u256, string>> g_units = static const vector<pair<u256, string>> g_units =

48
libethereum/BlockChain.cpp

@ -108,6 +108,20 @@ bytes BlockChain::createGenesisBlock()
} }
BlockChain::BlockChain(std::string _path, bool _killExisting) BlockChain::BlockChain(std::string _path, bool _killExisting)
{
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
open(_path, _killExisting);
}
BlockChain::~BlockChain()
{
close();
}
void BlockChain::open(std::string _path, bool _killExisting)
{ {
if (_path.empty()) if (_path.empty())
_path = Defaults::get()->m_dbPath; _path = Defaults::get()->m_dbPath;
@ -127,10 +141,6 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!m_extrasDB) if (!m_extrasDB)
throw DatabaseAlreadyOpen(); throw DatabaseAlreadyOpen();
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
if (!details(m_genesisHash)) if (!details(m_genesisHash))
{ {
// Insert details of genesis block. // Insert details of genesis block.
@ -150,11 +160,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
cnote << "Opened blockchain DB. Latest: " << currentHash(); cnote << "Opened blockchain DB. Latest: " << currentHash();
} }
BlockChain::~BlockChain() void BlockChain::close()
{ {
cnote << "Closing blockchain DB"; cnote << "Closing blockchain DB";
delete m_extrasDB; delete m_extrasDB;
delete m_db; delete m_db;
m_lastBlockHash = m_genesisHash;
m_details.clear();
m_blooms.clear();
m_traces.clear();
m_cache.clear();
} }
template <class T, class V> template <class T, class V>
@ -245,21 +260,24 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
auto newHash = BlockInfo::headerHash(_block); auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first! // Check block doesn't already exist first!
if (details(newHash)) if (isKnown(newHash))
{ {
clog(BlockChainNote) << newHash << ": Not new."; clog(BlockChainNote) << newHash << ": Not new.";
throw AlreadyHaveBlock(); throw AlreadyHaveBlock();
} }
// Work out its number as the parent's number + 1 // Work out its number as the parent's number + 1
auto pd = details(bi.parentHash); if (!isKnown(bi.parentHash))
if (!pd)
{ {
clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash; clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash;
// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
throw UnknownParent(); throw UnknownParent();
} }
auto pd = details(bi.parentHash);
if (!pd)
cwarn << "Odd: details is returning false despite block known:" << RLP(pd.rlp());
// Check it's not crazy // Check it's not crazy
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{ {
@ -432,6 +450,20 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
return ret; return ret;
} }
bool BlockChain::isKnown(h256 _hash) const
{
if (_hash == m_genesisHash)
return true;
{
ReadGuard l(x_cache);
if (m_cache.count(_hash))
return true;
}
string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
return !!d.size();
}
bytes BlockChain::block(h256 _hash) const bytes BlockChain::block(h256 _hash) const
{ {
if (_hash == m_genesisHash) if (_hash == m_genesisHash)

8
libethereum/BlockChain.h

@ -70,6 +70,8 @@ public:
BlockChain(std::string _path, bool _killExisting = false); BlockChain(std::string _path, bool _killExisting = false);
~BlockChain(); ~BlockChain();
void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so. /// To be called from main loop every 100ms or so.
void process(); void process();
@ -85,6 +87,9 @@ public:
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
h256s import(bytes const& _block, OverlayDB const& _stateDB); h256s import(bytes const& _block, OverlayDB const& _stateDB);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); } BlockDetails details() const { return details(currentHash()); }
@ -143,6 +148,9 @@ public:
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const; h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
private: private:
void open(std::string _path, bool _killExisting = false);
void close();
template<class T, unsigned N> T queryExtras(h256 _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const template<class T, unsigned N> T queryExtras(h256 _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
{ {
{ {

9
libethereum/BlockQueue.cpp

@ -74,21 +74,24 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
// Check it's not in the future // Check it's not in the future
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
cblockq << "OK - queued for future.";
}
else else
{ {
// We now know it. // We now know it.
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(bi.parentHash)) if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{ {
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
// cnote << "OK - queued for future."; cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h); m_unknownSet.insert(h);
} }
else else
{ {
// If valid, append to blocks. // If valid, append to blocks.
// cnote << "OK - ready for chain insertion."; cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes()); m_ready.push_back(_block.toBytes());
m_readySet.insert(h); m_readySet.insert(h);

5
libethereum/BlockQueue.h

@ -34,7 +34,7 @@ namespace eth
class BlockChain; class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 7; }; struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>() #define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
/** /**
@ -64,6 +64,9 @@ public:
/// Get information on the items queued. /// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); } std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
/// Clear everything.
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
private: private:
void noteReadyWithoutWriteGuard(h256 _b); void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block); void notePresentWithoutWriteGuard(bytesConstRef _block);

284
libethereum/Client.cpp

@ -53,94 +53,107 @@ void VersionChecker::setOk()
} }
} }
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath, bool _forceClean):
m_clientVersion(_clientVersion),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB)
{
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
work();
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId): Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId):
Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean), m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)), m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB), m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB) m_postMine(Address(), m_stateDB)
{ {
m_extHost = _extNet->registerCapability(new EthereumHost(m_bc, _networkId)); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
// setMiningThreads(); setMiningThreads();
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
m_vc.setOk(); m_vc.setOk();
work(); doWork();
startWorking();
} }
Client::~Client() Client::~Client()
{ {
if (m_work) stopWorking();
{
if (m_workState.load(std::memory_order_acquire) == Active)
m_workState.store(Deleting, std::memory_order_release);
while (m_workState.load(std::memory_order_acquire) != Deleted)
this_thread::sleep_for(chrono::milliseconds(10));
m_work->join();
m_work.reset(nullptr);
}
stopNetwork();
} }
void Client::ensureWorking() void Client::setNetworkId(u256 _n)
{ {
static const char* c_threadName = "eth"; if (auto h = m_host.lock())
h->setNetworkId(_n);
}
if (!m_work) DownloadMan const* Client::downloadMan() const { if (auto h = m_host.lock()) return &(h->downloadMan()); return nullptr; }
m_work.reset(new thread([&]() bool Client::isSyncing() const { if (auto h = m_host.lock()) return h->isSyncing(); return false; }
{
setThreadName(c_threadName); void Client::doneWorking()
m_workState.store(Active, std::memory_order_release); {
while (m_workState.load(std::memory_order_acquire) != Deleting) // Synchronise the state according to the head of the block chain.
work(); // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
m_workState.store(Deleted, std::memory_order_release); WriteGuard l(x_stateDB);
m_preMine.sync(m_bc);
// Synchronise the state according to the head of the block chain. m_postMine = m_preMine;
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB);
m_preMine.sync(m_bc);
m_postMine = m_preMine;
}));
} }
void Client::flushTransactions() void Client::flushTransactions()
{ {
work(); doWork();
}
void Client::killChain()
{
bool wasMining = isMining();
if (wasMining)
stopMining();
stopWorking();
m_tq.clear();
m_bq.clear();
m_miners.clear();
m_preMine = State();
m_postMine = State();
{
WriteGuard l(x_stateDB);
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), true);
}
m_bc.reopen(Defaults::dbPath(), true);
m_preMine = State(Address(), m_stateDB);
m_postMine = State(Address(), m_stateDB);
if (auto h = m_host.lock())
h->reset();
doWork();
setMiningThreads(0);
startWorking();
if (wasMining)
startMining();
} }
void Client::clearPending() void Client::clearPending()
{ {
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size())
return;
h256Set changeds; h256Set changeds;
for (unsigned i = 0; i < m_postMine.pending().size(); ++i) {
appendFromNewPending(m_postMine.bloom(i), changeds); WriteGuard l(x_stateDB);
changeds.insert(PendingChangedFilter); if (!m_postMine.pending().size())
m_postMine = m_preMine; return;
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
appendFromNewPending(m_postMine.bloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_postMine = m_preMine;
}
if (!m_extHost.lock())
{ {
ReadGuard l(x_miners); ReadGuard l(x_miners);
for (auto& m: m_miners) for (auto& m: m_miners)
m.noteStateChange(); m.noteStateChange();
} }
noteChanged(changeds); noteChanged(changeds);
} }
@ -211,111 +224,10 @@ void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
o_changed.insert(i.first); o_changed.insert(i.first);
} }
void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHost, unsigned short _port, NodeMode _mode, unsigned _peers, string const& _publicIP, bool _upnp, u256 _networkId)
{
static const char* c_threadName = "net";
{
UpgradableGuard l(x_net);
if (m_net.get())
return;
{
UpgradeGuard ul(l);
if (!m_workNet)
m_workNet.reset(new thread([&]()
{
setThreadName(c_threadName);
m_workNetState.store(Active, std::memory_order_release);
while (m_workNetState.load(std::memory_order_acquire) != Deleting)
workNet();
m_workNetState.store(Deleted, std::memory_order_release);
}));
if (!m_extHost.lock())
{
try
{
m_net.reset(new Host(m_clientVersion, _listenPort, _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 Host(m_clientVersion, 0, _publicIP, _upnp));
}
if (_mode == NodeMode::Full)
m_net->registerCapability(new EthereumHost(m_bc, _networkId));
}
}
m_net->setIdealPeerCount(_peers);
}
if (!m_extHost.lock())
if (_seedHost.size())
connect(_seedHost, _port);
ensureWorking();
}
void Client::stopNetwork()
{
UpgradableGuard l(x_net);
if (m_workNet)
{
if (m_workNetState.load(std::memory_order_acquire) == Active)
m_workNetState.store(Deleting, std::memory_order_release);
while (m_workNetState.load(std::memory_order_acquire) != Deleted)
this_thread::sleep_for(chrono::milliseconds(10));
m_workNet->join();
}
if (m_net)
{
UpgradeGuard ul(l);
m_net.reset(nullptr);
m_workNet.reset(nullptr);
}
}
std::vector<PeerInfo> Client::peers()
{
ReadGuard l(x_net);
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
size_t Client::peerCount() const
{
ReadGuard l(x_net);
return m_net ? m_net->peerCount() : 0;
}
void Client::setIdealPeerCount(size_t _n) const
{
ReadGuard l(x_net);
if (m_net)
return m_net->setIdealPeerCount(_n);
}
bytes Client::savePeers()
{
ReadGuard l(x_net);
if (m_net)
return m_net->savePeers();
return bytes();
}
void Client::restorePeers(bytesConstRef _saved)
{
ReadGuard l(x_net);
if (m_net)
return m_net->restorePeers(_saved);
}
void Client::setForceMining(bool _enable) void Client::setForceMining(bool _enable)
{ {
m_forceMining = _enable; m_forceMining = _enable;
if (!m_extHost.lock()) if (!m_host.lock())
{ {
ReadGuard l(x_miners); ReadGuard l(x_miners);
for (auto& m: m_miners) for (auto& m: m_miners)
@ -323,19 +235,8 @@ void Client::setForceMining(bool _enable)
} }
} }
void Client::connect(std::string const& _seedHost, unsigned short _port)
{
ReadGuard l(x_net);
if (!m_net.get())
return;
m_net->connect(_seedHost, _port);
}
void Client::setMiningThreads(unsigned _threads) void Client::setMiningThreads(unsigned _threads)
{ {
if (m_extHost.lock())
return;
stopMining(); stopMining();
auto t = _threads ? _threads : thread::hardware_concurrency(); auto t = _threads ? _threads : thread::hardware_concurrency();
@ -350,8 +251,6 @@ void Client::setMiningThreads(unsigned _threads)
MineProgress Client::miningProgress() const MineProgress Client::miningProgress() const
{ {
MineProgress ret; MineProgress ret;
if (m_extHost.lock())
return ret;
ReadGuard l(x_miners); ReadGuard l(x_miners);
for (auto& m: m_miners) for (auto& m: m_miners)
ret.combine(m.miningProgress()); ret.combine(m.miningProgress());
@ -361,8 +260,6 @@ MineProgress Client::miningProgress() const
std::list<MineInfo> Client::miningHistory() std::list<MineInfo> Client::miningHistory()
{ {
std::list<MineInfo> ret; std::list<MineInfo> ret;
if (m_extHost.lock())
return ret;
ReadGuard l(x_miners); ReadGuard l(x_miners);
if (m_miners.empty()) if (m_miners.empty())
@ -404,7 +301,7 @@ void Client::setupState(State& _s)
void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
ensureWorking(); startWorking();
Transaction t; Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
@ -446,7 +343,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{ {
ensureWorking(); startWorking();
Transaction t; Transaction t;
{ {
@ -466,47 +363,18 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
void Client::inject(bytesConstRef _rlp) void Client::inject(bytesConstRef _rlp)
{ {
ensureWorking(); startWorking();
m_tq.attemptImport(_rlp); m_tq.attemptImport(_rlp);
} }
void Client::workNet() void Client::doWork()
{
// Process network events.
// Synchronise block chain with network.
// Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks.
{
ReadGuard l(x_net);
if (m_net)
{
cwork << "NETWORK";
m_net->process(); // must be in guard for now since it uses the blockchain.
// returns h256Set as block hashes, once for each block that has come in/gone out.
if (m_net->cap<EthereumHost>())
{
cwork << "NET <==> TQ ; CHAIN ==> NET ==> BQ";
m_net->cap<EthereumHost>()->sync(m_tq, m_bq);
cwork << "TQ:" << m_tq.items() << "; BQ:" << m_bq.items();
}
}
}
if (auto h = m_extHost.lock())
h->sync(m_tq, m_bq);
this_thread::sleep_for(chrono::milliseconds(1));
}
void Client::work()
{ {
// TODO: Use condition variable rather than polling. // TODO: Use condition variable rather than polling.
cworkin << "WORK"; cworkin << "WORK";
h256Set changeds; h256Set changeds;
if (!m_extHost.lock())
{ {
ReadGuard l(x_miners); ReadGuard l(x_miners);
for (auto& m: m_miners) for (auto& m: m_miners)
@ -557,7 +425,8 @@ void Client::work()
cwork << "preSTATE <== CHAIN"; cwork << "preSTATE <== CHAIN";
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{ {
cnote << "New block on chain: Restarting mining operation."; if (isMining())
cnote << "New block on chain: Restarting mining operation.";
m_postMine = m_preMine; m_postMine = m_preMine;
rsm = true; rsm = true;
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
@ -573,11 +442,12 @@ void Client::work()
appendFromNewPending(i, changeds); appendFromNewPending(i, changeds);
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
cnote << "Additional transaction ready: Restarting mining operation."; if (isMining())
cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true; rsm = true;
} }
} }
if (!m_extHost.lock() && rsm) if (rsm)
{ {
ReadGuard l(x_miners); ReadGuard l(x_miners);
for (auto& m: m_miners) for (auto& m: m_miners)

68
libethereum/Client.h

@ -29,6 +29,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libevm/FeeStructure.h> #include <libevm/FeeStructure.h>
#include <libethcore/Dagger.h> #include <libethcore/Dagger.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
@ -47,6 +48,7 @@ namespace eth
{ {
class Client; class Client;
class DownloadMan;
enum ClientWorkState enum ClientWorkState
{ {
@ -108,14 +110,11 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
/** /**
* @brief Main API hub for interfacing with Ethereum. * @brief Main API hub for interfacing with Ethereum.
*/ */
class Client: public MinerHost, public Interface class Client: public MinerHost, public Interface, Worker
{ {
friend class Miner; friend class Miner;
public: public:
/// Original Constructor.
explicit Client(std::string const& _clientVersion, Address _us = Address(), std::string const& _dbPath = std::string(), bool _forceClean = false);
/// New-style Constructor. /// New-style Constructor.
explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0); explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0);
@ -165,6 +164,9 @@ public:
// [EXTRA API]: // [EXTRA API]:
/// @returns the length of the chain.
virtual unsigned number() const { return m_bc.number(); }
/// Get a map containing each of the pending transactions. /// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions(). /// @TODO: Remove in favour of transactions().
Transactions pending() const { return m_postMine.pending(); } Transactions pending() const { return m_postMine.pending(); }
@ -192,32 +194,6 @@ public:
/// Get the object representing the current canonical blockchain. /// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return m_bc; } BlockChain const& blockChain() const { return m_bc; }
// Misc stuff:
void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
// Network stuff:
/// Get information on the current peer set.
std::vector<p2p::PeerInfo> peers();
/// Same as peers().size(), but more efficient.
size_t peerCount() const;
/// Same as peers().size(), but more efficient.
void setIdealPeerCount(size_t _n) 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, u256 _networkId = 0);
/// Connect to a particular peer.
void connect(std::string const& _seedHost, unsigned short _port = 30303);
/// Stop the network subsystem.
void stopNetwork();
/// Is the network subsystem up?
bool haveNetwork() { ReadGuard l(x_net); return !!m_net; }
/// Save peers
bytes savePeers();
/// Restore peers
void restorePeers(bytesConstRef _saved);
// Mining stuff: // Mining stuff:
/// Check block validity prior to mining. /// Check block validity prior to mining.
@ -243,7 +219,7 @@ public:
unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); } unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
/// Start mining. /// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread /// NOT thread-safe - call it & stopMining only from a single thread
void startMining() { ensureWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); } void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
/// Stop mining. /// Stop mining.
/// NOT thread-safe /// NOT thread-safe
void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); } void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
@ -254,19 +230,22 @@ public:
/// Get and clear the mining history. /// Get and clear the mining history.
std::list<MineInfo> miningHistory(); std::list<MineInfo> miningHistory();
// Debug stuff:
DownloadMan const* downloadMan() const;
bool isSyncing() const;
/// Sets the network id.
void setNetworkId(u256 _n);
/// Clears pending transactions. Just for debug use. /// Clears pending transactions. Just for debug use.
void clearPending(); void clearPending();
/// Kills the blockchain. Just for debug use.
void killChain();
private: private:
/// Ensure the worker thread is running. Needed for blockchain maintenance & mining.
void ensureWorking();
/// Do some work. Handles blockchain maintenance and mining. /// Do some work. Handles blockchain maintenance and mining.
/// @param _justQueue If true will only processing the transaction queues. virtual void doWork();
void work();
/// Do some work on the network. virtual void doneWorking();
void workNet();
/// Overrides for being a mining host. /// Overrides for being a mining host.
virtual void setupState(State& _s); virtual void setupState(State& _s);
@ -291,26 +270,17 @@ private:
State asOf(int _h) const; State asOf(int _h) const;
State asOf(unsigned _h) const; State asOf(unsigned _h) const;
std::string m_clientVersion; ///< Our end-application client's name/version.
VersionChecker m_vc; ///< Dummy object to check & update the protocol version. VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
BlockChain m_bc; ///< Maintains block database. BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
// TODO: remove in favour of copying m_stateDB as required and thread-safing/copying State. Have a good think about what state objects there should be. Probably want 4 (pre, post, mining, user-visible).
mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client. State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::unique_ptr<std::thread> m_workNet; ///< The network thread. std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::atomic<ClientWorkState> m_workNetState;
mutable boost::shared_mutex x_net; ///< Lock for the network existance.
std::unique_ptr<p2p::Host> m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::weak_ptr<EthereumHost> m_extHost; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::unique_ptr<std::thread> m_work; ///< The work thread.
std::atomic<ClientWorkState> m_workState;
std::vector<Miner> m_miners; std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners; mutable boost::shared_mutex x_miners;

17
libethereum/CommonNet.h

@ -33,11 +33,17 @@ namespace dev
namespace eth namespace eth
{ {
#if ETH_DEBUG
static const unsigned c_maxHashes = 64; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 64; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 32; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#else
static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#endif
class OverlayDB; class OverlayDB;
class BlockChain; class BlockChain;
class TransactionQueue; class TransactionQueue;
@ -55,5 +61,14 @@ enum EthereumPacket
BlocksPacket, BlocksPacket,
}; };
enum class Grabbing
{
State,
Hashes,
Chain,
ChainHelper,
Nothing
};
} }
} }

75
libethereum/DownloadMan.cpp

@ -0,0 +1,75 @@
/*
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 DownloadMan.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "DownloadMan.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
DownloadSub::DownloadSub(DownloadMan& _man): m_man(&_man)
{
WriteGuard l(m_man->x_subs);
m_man->m_subs.insert(this);
}
DownloadSub::~DownloadSub()
{
if (m_man)
{
WriteGuard l(m_man->x_subs);
m_man->m_subs.erase(this);
}
}
h256Set DownloadSub::nextFetch(unsigned _n)
{
Guard l(m_fetch);
if (m_remaining.size())
return m_remaining;
m_asked.clear();
m_indices.clear();
m_remaining.clear();
if (!m_man)
return h256Set();
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
if (m_asked.empty())
m_asked = (~(m_man->taken(true) + m_attempted)).lowest(_n);
m_attempted += m_asked;
for (auto i: m_asked)
{
auto x = m_man->m_chain[i];
m_remaining.insert(x);
m_indices[x] = i;
}
return m_remaining;
}
void DownloadSub::noteBlock(h256 _hash)
{
Guard l(m_fetch);
if (m_man && m_indices.count(_hash))
m_man->m_blocksGot += m_indices[_hash];
m_remaining.erase(_hash);
}

136
libethereum/DownloadMan.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 DownloadMan.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <vector>
#include <set>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
namespace eth
{
class DownloadMan;
class DownloadSub
{
friend class DownloadMan;
public:
DownloadSub(DownloadMan& _man);
~DownloadSub();
/// Finished last fetch - grab the next bunch of block hashes to download.
h256Set nextFetch(unsigned _n);
/// Note that we've received a particular block.
void noteBlock(h256 _hash);
/// Nothing doing here.
void doneFetch() { resetFetch(); }
RangeMask<unsigned> const& asked() const { return m_asked; }
RangeMask<unsigned> const& attemped() const { return m_attempted; }
private:
void resetFetch() // Called by DownloadMan when we need to reset the download.
{
Guard l(m_fetch);
m_remaining.clear();
m_indices.clear();
m_asked.clear();
m_attempted.clear();
}
DownloadMan* m_man = nullptr;
Mutex m_fetch;
h256Set m_remaining;
std::map<h256, unsigned> m_indices;
RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
};
class DownloadMan
{
friend class DownloadSub;
public:
~DownloadMan()
{
for (auto i: m_subs)
i->m_man = nullptr;
}
void resetToChain(h256s const& _chain)
{
{
ReadGuard l(x_subs);
for (auto i: m_subs)
i->resetFetch();
}
m_chain.clear();
m_chain.reserve(_chain.size());
for (auto i = _chain.rbegin(); i != _chain.rend(); ++i)
m_chain.push_back(*i);
m_blocksGot = RangeMask<unsigned>(0, m_chain.size());
}
RangeMask<unsigned> taken(bool _desperate = false) const
{
auto ret = m_blocksGot;
if (!_desperate)
{
ReadGuard l(x_subs);
for (auto i: m_subs)
ret += i->m_asked;
}
return ret;
}
bool isComplete() const
{
return m_blocksGot.full();
}
h256s chain() const { return m_chain; }
void foreachSub(std::function<void(DownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }
unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); }
RangeMask<unsigned> blocksGot() const { return m_blocksGot; }
private:
h256s m_chain;
RangeMask<unsigned> m_blocksGot;
mutable SharedMutex x_subs;
std::set<DownloadSub*> m_subs;
};
}
}

265
libethereum/EthereumHost.cpp

@ -15,9 +15,7 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file EthereumHost.cpp /** @file EthereumHost.cpp
* @authors: * @author Gav Wood <i@gavwood.com>
* Gav Wood <i@gavwood.com>
* Eric Lombrozo <elombrozo@gmail.com>
* @date 2014 * @date 2014
*/ */
@ -34,16 +32,21 @@
#include "TransactionQueue.h" #include "TransactionQueue.h"
#include "BlockQueue.h" #include "BlockQueue.h"
#include "EthereumPeer.h" #include "EthereumPeer.h"
#include "DownloadMan.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace p2p; using namespace p2p;
EthereumHost::EthereumHost(BlockChain const& _ch, u256 _networkId): EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability<EthereumPeer>(), HostCapability<EthereumPeer>(),
m_chain (&_ch), Worker ("ethsync"),
m_chain (_ch),
m_tq (_tq),
m_bq (_bq),
m_networkId (_networkId) m_networkId (_networkId)
{ {
m_latestBlockSent = _ch.currentHash();
} }
EthereumHost::~EthereumHost() EthereumHost::~EthereumHost()
@ -52,36 +55,12 @@ EthereumHost::~EthereumHost()
i->cap<EthereumPeer>()->giveUpOnFetch(); i->cap<EthereumPeer>()->giveUpOnFetch();
} }
h256Set EthereumHost::neededBlocks(h256Set const& _exclude)
{
Guard l(x_blocksNeeded);
h256Set ret;
if (m_blocksNeeded.size())
{
int s = m_blocksNeeded.size() - 1;
for (; ret.size() < c_maxBlocksAsk && s < (int)m_blocksNeeded.size() && s >= 0; --s)
if (!_exclude.count(m_blocksNeeded[s]))
{
auto it = m_blocksNeeded.begin() + s;
ret.insert(*it);
m_blocksOnWay.insert(*it);
m_blocksNeeded.erase(it);
}
}
if (!ret.size())
for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end() && !_exclude.count(*i); ++i)
ret.insert(*i);
clog(NetMessageSummary) << "Asking for" << ret.size() << "blocks that we don't yet have." << m_blocksNeeded.size() << "blocks still needed," << m_blocksOnWay.size() << "blocks on way.";
return ret;
}
bool EthereumHost::ensureInitialised(TransactionQueue& _tq) bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
{ {
if (m_latestBlockSent == h256()) if (!m_latestBlockSent)
{ {
// First time - just initialise. // First time - just initialise.
m_latestBlockSent = m_chain->currentHash(); m_latestBlockSent = m_chain.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged(); clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();
for (auto const& i: _tq.transactions()) for (auto const& i: _tq.transactions())
@ -91,25 +70,98 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
return false; return false;
} }
void EthereumHost::noteDoneBlocks() void EthereumHost::noteHavePeerState(EthereumPeer* _who)
{
clog(NetAllDetail) << "Have peer state.";
// if already downloading hash-chain, ignore.
if (m_grabbing != Grabbing::Nothing)
{
clog(NetAllDetail) << "Already downloading chain. Just set to help out.";
_who->ensureGettingChain();
return;
}
// otherwise check to see if we should be downloading...
_who->tryGrabbingHashChain();
}
void EthereumHost::updateGrabbing(Grabbing _g)
{
m_grabbing = _g;
if (_g == Grabbing::Nothing)
readyForSync();
else if (_g == Grabbing::Chain)
for (auto j: peers())
j->cap<EthereumPeer>()->ensureGettingChain();
}
void EthereumHost::noteHaveChain(EthereumPeer* _from)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
{
_from->m_grabbing = Grabbing::Nothing;
updateGrabbing(Grabbing::Nothing);
return;
}
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain.details().totalDifficulty << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if (td < m_chain.details().totalDifficulty || (td == m_chain.details().totalDifficulty && m_chain.currentHash() == _from->m_latestHash))
{
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
_from->m_grabbing = Grabbing::Nothing;
updateGrabbing(Grabbing::Nothing);
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue [latest now" << _from->m_latestHash.abridged() << ", was" << m_latestBlockSent.abridged() << "]";
// Looks like it's the best yet for total difficulty. Set to download.
m_man.resetToChain(_from->m_neededBlocks);
m_latestBlockSent = _from->m_latestHash;
_from->m_grabbing = Grabbing::Chain;
updateGrabbing(Grabbing::Chain);
}
void EthereumHost::readyForSync()
{
// start grabbing next hash chain if there is one.
for (auto j: peers())
{
j->cap<EthereumPeer>()->tryGrabbingHashChain();
if (j->cap<EthereumPeer>()->m_grabbing == Grabbing::Hashes)
{
m_grabbing = Grabbing::Hashes;
return;
}
}
clog(NetNote) << "No more peers to sync with.";
}
void EthereumHost::noteDoneBlocks(EthereumPeer* _who)
{ {
clog(NetNote) << "Peer given up on blocks fetch."; if (m_man.isComplete())
if (m_blocksOnWay.empty()) {
// Done our chain-get.
clog(NetNote) << "Chain download complete.";
updateGrabbing(Grabbing::Nothing);
}
if (_who->m_grabbing == Grabbing::Chain)
{ {
// Done our chain-get. // Done our chain-get.
if (m_blocksNeeded.size()) clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks."; // TODO: note that peer is BADBADBAD!
else updateGrabbing(Grabbing::Nothing);
clog(NetNote) << "No more blocks to get.";
m_latestBlockSent = m_chain->currentHash();
} }
} }
bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data) bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
{ {
Guard l(x_blocksNeeded); if (!m_chain.details(_hash))
m_blocksOnWay.erase(_hash);
if (!m_chain->details(_hash))
{ {
lock_guard<recursive_mutex> l(m_incomingLock); lock_guard<recursive_mutex> l(m_incomingLock);
m_incomingBlocks.push_back(_data.toBytes()); m_incomingBlocks.push_back(_data.toBytes());
@ -118,81 +170,96 @@ bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
return false; return false;
} }
bool EthereumHost::sync(TransactionQueue& _tq, BlockQueue& _bq) void EthereumHost::doWork()
{ {
bool netChange = ensureInitialised(_tq); bool netChange = ensureInitialised(m_tq);
auto h = m_chain->currentHash(); auto h = m_chain.currentHash();
maintainTransactions(_tq, h); maintainTransactions(m_tq, h);
maintainBlocks(_bq, h); maintainBlocks(m_bq, h);
return netChange; // return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
} }
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash) void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash)
{ {
bool resendAll = (_currentHash != m_latestBlockSent); bool resendAll = (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && _currentHash != m_latestBlockSent);
{
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it) lock_guard<recursive_mutex> l(m_incomingLock);
if (_tq.import(&*it)) for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce... if (_tq.import(&*it))
else {}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on. else
m_incomingTransactions.clear(); m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
}
// Send any new transactions. // Send any new transactions.
for (auto const& p: peers()) for (auto const& p: peers())
{ {
auto ep = p->cap<EthereumPeer>(); auto ep = p->cap<EthereumPeer>();
bytes b; if (ep)
unsigned n = 0; {
for (auto const& i: _tq.transactions()) bytes b;
if ((!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)) || ep->m_requireTransactions || resendAll) unsigned n = 0;
for (auto const& i: _tq.transactions())
if ((!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)) || ep->m_requireTransactions || resendAll)
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
ep->clearKnownTransactions();
if (n)
{ {
b += i.second; RLPStream ts;
++n; EthereumPeer::prep(ts);
m_transactionsSent.insert(i.first); ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
ep->send(&b);
} }
if (n) ep->m_requireTransactions = false;
{
RLPStream ts;
EthereumPeer::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
ep->send(&b);
} }
ep->m_knownTransactions.clear();
ep->m_requireTransactions = false;
} }
} }
void EthereumHost::reset()
{
m_grabbing = Grabbing::Nothing;
m_man.resetToChain(h256s());
m_incomingTransactions.clear();
m_incomingBlocks.clear();
m_latestBlockSent = h256();
m_transactionsSent.clear();
}
void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash) void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
{ {
// Import new blocks // Import new blocks
{ {
lock_guard<recursive_mutex> l(m_incomingLock); lock_guard<recursive_mutex> l(m_incomingLock);
for (auto it = m_incomingBlocks.rbegin(); it != m_incomingBlocks.rend(); ++it) for (auto it = m_incomingBlocks.rbegin(); it != m_incomingBlocks.rend(); ++it)
if (_bq.import(&*it, *m_chain)) if (_bq.import(&*it, m_chain))
{} {}
else{} // TODO: don't forward it. else{} // TODO: don't forward it.
m_incomingBlocks.clear(); m_incomingBlocks.clear();
} }
// If we've finished our initial sync... // If we've finished our initial sync send any new blocks.
{ if (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
Guard l(x_blocksNeeded);
if (m_blocksOnWay.size())
return;
}
// ...send any new blocks.
if (m_latestBlockSent != _currentHash)
{ {
RLPStream ts; RLPStream ts;
EthereumPeer::prep(ts); EthereumPeer::prep(ts);
bytes bs; bytes bs;
unsigned c = 0; unsigned c = 0;
for (auto h: m_chain->treeRoute(m_latestBlockSent, _currentHash, nullptr, false, true)) for (auto h: m_chain.treeRoute(m_latestBlockSent, _currentHash, nullptr, false, true))
{ {
bs += m_chain->block(h); bs += m_chain.block(h);
++c; ++c;
} }
clog(NetMessageSummary) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; clog(NetMessageSummary) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
@ -204,6 +271,7 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
for (auto j: peers()) for (auto j: peers())
{ {
auto p = j->cap<EthereumPeer>(); auto p = j->cap<EthereumPeer>();
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash)) if (!p->m_knownBlocks.count(_currentHash))
p->send(&b); p->send(&b);
p->m_knownBlocks.clear(); p->m_knownBlocks.clear();
@ -211,32 +279,3 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
m_latestBlockSent = _currentHash; m_latestBlockSent = _currentHash;
} }
} }
void EthereumHost::noteHaveChain(EthereumPeer* _from)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
return;
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain->details().totalDifficulty << "," << m_totalDifficultyOfNeeded << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if ((m_totalDifficultyOfNeeded && td < m_totalDifficultyOfNeeded) || td < m_chain->details().totalDifficulty)
{
clog(NetNote) << "Difficulty of hashchain LOWER. Ignoring.";
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue.";
// Looks like it's the best yet for total difficulty. Set to download.
{
Guard l(x_blocksNeeded);
m_blocksNeeded = _from->m_neededBlocks;
m_blocksOnWay.clear();
m_totalDifficultyOfNeeded = td;
}
for (auto j: peers())
j->cap<EthereumPeer>()->restartGettingChain();
}

44
libethereum/EthereumHost.h

@ -29,10 +29,13 @@
#include <utility> #include <utility>
#include <thread> #include <thread>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CommonNet.h" #include "CommonNet.h"
#include "EthereumPeer.h" #include "EthereumPeer.h"
#include "DownloadMan.h"
namespace dev namespace dev
{ {
@ -49,31 +52,41 @@ class BlockQueue;
* @brief The EthereumHost class * @brief The EthereumHost class
* @warning None of this is thread-safe. You have been warned. * @warning None of this is thread-safe. You have been warned.
*/ */
class EthereumHost: public p2p::HostCapability<EthereumPeer> class EthereumHost: public p2p::HostCapability<EthereumPeer>, Worker
{ {
friend class EthereumPeer; friend class EthereumPeer;
public: public:
/// Start server, but don't listen. /// Start server, but don't listen.
EthereumHost(BlockChain const& _ch, u256 _networkId); EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId);
/// Will block on network process events. /// Will block on network process events.
virtual ~EthereumHost(); virtual ~EthereumHost();
unsigned protocolVersion() const { return c_protocolVersion; } unsigned protocolVersion() const { return c_protocolVersion; }
u256 networkId() const { return m_networkId; } u256 networkId() const { return m_networkId; }
void setNetworkId(u256 _n) { m_networkId = _n; }
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void reset();
bool sync(TransactionQueue&, BlockQueue& _bc);
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return m_grabbing == Grabbing::Chain; }
private: private:
void noteHavePeerState(EthereumPeer* _who);
/// Session wants to pass us a block that we might not have. /// Session wants to pass us a block that we might not have.
/// @returns true if we didn't have it. /// @returns true if we didn't have it.
bool noteBlock(h256 _hash, bytesConstRef _data); bool noteBlock(h256 _hash, bytesConstRef _data);
/// Session has finished getting the chain of hashes. /// Session has finished getting the chain of hashes.
void noteHaveChain(EthereumPeer* _who); void noteHaveChain(EthereumPeer* _who);
/// Called when the peer can no longer provide us with any needed blocks. /// Called when the peer can no longer provide us with any needed blocks.
void noteDoneBlocks(); void noteDoneBlocks(EthereumPeer* _who);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
void doWork();
/// Called by peer to add incoming transactions.
void addIncomingTransaction(bytes const& _bytes) { std::lock_guard<std::recursive_mutex> l(m_incomingLock); m_incomingTransactions.push_back(_bytes); }
void maintainTransactions(TransactionQueue& _tq, h256 _currentBlock); void maintainTransactions(TransactionQueue& _tq, h256 _currentBlock);
void maintainBlocks(BlockQueue& _bq, h256 _currentBlock); void maintainBlocks(BlockQueue& _bq, h256 _currentBlock);
@ -84,26 +97,33 @@ private:
h256Set neededBlocks(h256Set const& _exclude); h256Set neededBlocks(h256Set const& _exclude);
/// Check to see if the network peer-state initialisation has happened. /// Check to see if the network peer-state initialisation has happened.
virtual bool isInitialised() const { return m_latestBlockSent; } 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. /// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(TransactionQueue& _tq); bool ensureInitialised(TransactionQueue& _tq);
BlockChain const* m_chain = nullptr; virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
void readyForSync();
void updateGrabbing(Grabbing _g);
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue& m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
u256 m_networkId; u256 m_networkId;
Grabbing m_grabbing = Grabbing::Nothing; // TODO: needs to be thread-safe & switch to just having a peer id.
mutable std::recursive_mutex m_incomingLock; mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_incomingTransactions; std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks; std::vector<bytes> m_incomingBlocks;
mutable std::mutex x_blocksNeeded; DownloadMan m_man;
u256 m_totalDifficultyOfNeeded;
h256s m_blocksNeeded;
h256Set m_blocksOnWay;
h256 m_latestBlockSent; h256 m_latestBlockSent;
std::set<h256> m_transactionsSent; h256Set m_transactionsSent;
}; };
} }

137
libethereum/EthereumPeer.cpp

@ -35,7 +35,8 @@ using namespace p2p;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " #define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h): EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h):
Capability(_s, _h) Capability(_s, _h),
m_sub(host()->m_man)
{ {
sendStatus(); sendStatus();
} }
@ -57,15 +58,15 @@ void EthereumPeer::sendStatus()
s.appendList(6) << StatusPacket s.appendList(6) << StatusPacket
<< host()->protocolVersion() << host()->protocolVersion()
<< host()->networkId() << host()->networkId()
<< host()->m_chain->details().totalDifficulty << host()->m_chain.details().totalDifficulty
<< host()->m_chain->currentHash() << host()->m_chain.currentHash()
<< host()->m_chain->genesisHash(); << host()->m_chain.genesisHash();
sealAndSend(s); sealAndSend(s);
} }
void EthereumPeer::startInitialSync() void EthereumPeer::startInitialSync()
{ {
// Grab trsansactions off them. // Grab transactions off them.
{ {
RLPStream s; RLPStream s;
prep(s).appendList(1); prep(s).appendList(1);
@ -73,16 +74,36 @@ void EthereumPeer::startInitialSync()
sealAndSend(s); sealAndSend(s);
} }
h256 c = host()->m_chain->currentHash(); host()->noteHavePeerState(this);
unsigned n = host()->m_chain->number(); }
u256 td = max(host()->m_chain->details().totalDifficulty, host()->m_totalDifficultyOfNeeded);
clogS(NetAllDetail) << "Initial sync. Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << host()->m_chain->details().totalDifficulty << "," << host()->m_totalDifficultyOfNeeded << ") versus " << m_totalDifficulty; void EthereumPeer::tryGrabbingHashChain()
if (td > m_totalDifficulty) {
// if already done this, then ignore.
if (m_grabbing != Grabbing::State)
{
clogS(NetAllDetail) << "Already synced with this peer.";
return;
}
h256 c = host()->m_chain.currentHash();
unsigned n = host()->m_chain.number();
u256 td = host()->m_chain.details().totalDifficulty;
clogS(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD:" << td << " versus " << m_totalDifficulty;
if (td >= m_totalDifficulty)
{
clogS(NetAllDetail) << "No. Our chain is better.";
m_grabbing = Grabbing::Nothing;
return; // All good - we have the better chain. return; // All good - we have the better chain.
}
// Our chain isn't better - grab theirs. // Our chain isn't better - grab theirs.
{ {
clogS(NetAllDetail) << "Yes. Their chain is better.";
host()->updateGrabbing(Grabbing::Hashes);
m_grabbing = Grabbing::Hashes;
RLPStream s; RLPStream s;
prep(s).appendList(3); prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk; s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
@ -93,19 +114,17 @@ void EthereumPeer::startInitialSync()
void EthereumPeer::giveUpOnFetch() void EthereumPeer::giveUpOnFetch()
{ {
clogS(NetNote) << "GIVE UP FETCH; can't get" << toString(m_askedBlocks); clogS(NetNote) << "GIVE UP FETCH";
if (m_askedBlocks.size())
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
{ {
Guard l (host()->x_blocksNeeded); host()->noteDoneBlocks(this);
host()->m_blocksNeeded.reserve(host()->m_blocksNeeded.size() + m_askedBlocks.size()); m_grabbing = Grabbing::Nothing;
for (auto i: m_askedBlocks)
{
m_failedBlocks.insert(i);
host()->m_blocksOnWay.erase(i);
host()->m_blocksNeeded.push_back(i);
}
m_askedBlocks.clear();
} }
m_sub.doneFetch();
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
} }
bool EthereumPeer::interpret(RLP const& _r) bool EthereumPeer::interpret(RLP const& _r)
@ -122,7 +141,7 @@ bool EthereumPeer::interpret(RLP const& _r)
clogS(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << ", TD:" << m_totalDifficulty << "=" << m_latestHash.abridged(); clogS(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << ", TD:" << m_totalDifficulty << "=" << m_latestHash.abridged();
if (genesisHash != host()->m_chain->genesisHash()) if (genesisHash != host()->m_chain.genesisHash())
disable("Invalid genesis hash"); disable("Invalid genesis hash");
if (m_protocolVersion != host()->protocolVersion()) if (m_protocolVersion != host()->protocolVersion())
disable("Invalid protocol version."); disable("Invalid protocol version.");
@ -138,33 +157,44 @@ bool EthereumPeer::interpret(RLP const& _r)
break; break;
} }
case TransactionsPacket: case TransactionsPacket:
{
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)"; clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)";
addRating(_r.itemCount() - 1); addRating(_r.itemCount() - 1);
lock_guard<recursive_mutex> l(host()->m_incomingLock);
for (unsigned i = 1; i < _r.itemCount(); ++i) for (unsigned i = 1; i < _r.itemCount(); ++i)
{ {
host()->m_incomingTransactions.push_back(_r[i].data().toBytes()); host()->addIncomingTransaction(_r[i].data().toBytes());
lock_guard<mutex> l(x_knownTransactions);
m_knownTransactions.insert(sha3(_r[i].data())); m_knownTransactions.insert(sha3(_r[i].data()));
} }
break; break;
}
case GetBlockHashesPacket: case GetBlockHashesPacket:
{ {
h256 later = _r[1].toHash<h256>(); h256 later = _r[1].toHash<h256>();
unsigned limit = _r[2].toInt<unsigned>(); unsigned limit = _r[2].toInt<unsigned>();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")"; clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")";
unsigned c = min<unsigned>(host()->m_chain->number(later), limit); unsigned c = min<unsigned>(max<unsigned>(1, host()->m_chain.number(later)) - 1, limit);
RLPStream s; RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket); prep(s).appendList(1 + c).append(BlockHashesPacket);
h256 p = host()->m_chain->details(later).parent; h256 p = host()->m_chain.details(later).parent;
for (unsigned i = 0; i < c; ++i, p = host()->m_chain->details(p).parent) for (unsigned i = 0; i < c; ++i, p = host()->m_chain.details(p).parent)
s << p; s << p;
sealAndSend(s); sealAndSend(s);
break; break;
} }
case BlockHashesPacket: case BlockHashesPacket:
{ {
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)"; clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreHashes");
if (m_grabbing != Grabbing::Hashes)
{
cwarn << "Peer giving us hashes when we didn't ask for them.";
break;
}
if (_r.itemCount() == 1) if (_r.itemCount() == 1)
{ {
host()->noteHaveChain(this); host()->noteHaveChain(this);
@ -173,7 +203,7 @@ bool EthereumPeer::interpret(RLP const& _r)
for (unsigned i = 1; i < _r.itemCount(); ++i) for (unsigned i = 1; i < _r.itemCount(); ++i)
{ {
auto h = _r[i].toHash<h256>(); auto h = _r[i].toHash<h256>();
if (host()->m_chain->details(h)) if (host()->m_chain.details(h))
{ {
host()->noteHaveChain(this); host()->noteHaveChain(this);
return true; return true;
@ -191,12 +221,12 @@ bool EthereumPeer::interpret(RLP const& _r)
case GetBlocksPacket: case GetBlocksPacket:
{ {
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)"; clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)";
// TODO: return the requested blocks. // return the requested blocks.
bytes rlp; bytes rlp;
unsigned n = 0; unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i) for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
{ {
auto b = host()->m_chain->block(_r[i].toHash<h256>()); auto b = host()->m_chain.block(_r[i].toHash<h256>());
if (b.size()) if (b.size())
{ {
rlp += b; rlp += b;
@ -209,22 +239,23 @@ bool EthereumPeer::interpret(RLP const& _r)
} }
case BlocksPacket: case BlocksPacket:
{ {
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)"; clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreBlocks");
if (_r.itemCount() == 1 && !m_askedBlocksChanged) if (_r.itemCount() == 1)
{ {
// Couldn't get any from last batch - probably got to this peer's latest block - just give up. // Couldn't get any from last batch - probably got to this peer's latest block - just give up.
m_sub.doneFetch();
giveUpOnFetch(); giveUpOnFetch();
} }
m_askedBlocksChanged = false;
unsigned used = 0; unsigned used = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i) for (unsigned i = 1; i < _r.itemCount(); ++i)
{ {
auto h = BlockInfo::headerHash(_r[i].data()); auto h = BlockInfo::headerHash(_r[i].data());
m_sub.noteBlock(h);
if (host()->noteBlock(h, _r[i].data())) if (host()->noteBlock(h, _r[i].data()))
used++; used++;
m_askedBlocks.erase(h); Guard l(x_knownBlocks);
m_knownBlocks.insert(h); m_knownBlocks.insert(h);
} }
addRating(used); addRating(used);
@ -236,15 +267,16 @@ bool EthereumPeer::interpret(RLP const& _r)
{ {
auto h = BlockInfo::headerHash(_r[i].data()); auto h = BlockInfo::headerHash(_r[i].data());
BlockInfo bi(_r[i].data()); BlockInfo bi(_r[i].data());
if (!host()->m_chain->details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash)) Guard l(x_knownBlocks);
if (!host()->m_chain.details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
{ {
unknownParents++; unknownParents++;
clogS(NetAllDetail) << "Unknown parent" << bi.parentHash << "of block" << h; clogS(NetAllDetail) << "Unknown parent" << bi.parentHash.abridged() << "of block" << h.abridged();
} }
else else
{ {
knownParents++; knownParents++;
clogS(NetAllDetail) << "Known parent" << bi.parentHash << "of block" << h; clogS(NetAllDetail) << "Known parent" << bi.parentHash.abridged() << "of block" << h.abridged();
} }
} }
} }
@ -258,21 +290,9 @@ bool EthereumPeer::interpret(RLP const& _r)
return true; return true;
} }
void EthereumPeer::restartGettingChain()
{
if (m_askedBlocks.size())
{
m_askedBlocksChanged = true; // So that we continue even if the Ask's reply is empty.
m_askedBlocks.clear(); // So that we restart once we get the Ask's reply.
m_failedBlocks.clear();
}
else
ensureGettingChain();
}
void EthereumPeer::ensureGettingChain() void EthereumPeer::ensureGettingChain()
{ {
if (m_askedBlocks.size()) if (m_grabbing == Grabbing::ChainHelper)
return; // Already asked & waiting for some. return; // Already asked & waiting for some.
continueGettingChain(); continueGettingChain();
@ -280,21 +300,20 @@ void EthereumPeer::ensureGettingChain()
void EthereumPeer::continueGettingChain() void EthereumPeer::continueGettingChain()
{ {
if (!m_askedBlocks.size()) if (m_grabbing != Grabbing::Chain)
m_askedBlocks = host()->neededBlocks(m_failedBlocks); m_grabbing = Grabbing::ChainHelper;
if (m_askedBlocks.size()) auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{ {
RLPStream s; RLPStream s;
prep(s); prep(s);
s.appendList(m_askedBlocks.size() + 1) << GetBlocksPacket; s.appendList(blocks.size() + 1) << GetBlocksPacket;
for (auto i: m_askedBlocks) for (auto const& i: blocks)
s << i; s << i;
sealAndSend(s); sealAndSend(s);
} }
else else
{ giveUpOnFetch();
clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have" << m_failedBlocks.size() << "of our needed blocks.";
host()->noteDoneBlocks();
}
} }

19
libethereum/EthereumPeer.h

@ -27,9 +27,12 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libp2p/Capability.h> #include <libp2p/Capability.h>
#include "CommonNet.h" #include "CommonNet.h"
#include "DownloadMan.h"
namespace dev namespace dev
{ {
@ -58,30 +61,34 @@ private:
void sendStatus(); void sendStatus();
void startInitialSync(); void startInitialSync();
void tryGrabbingHashChain();
/// Ensure that we are waiting for a bunch of blocks from our peer. /// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain(); void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer. /// Ensure that we are waiting for a bunch of blocks from our peer.
void continueGettingChain(); void continueGettingChain();
/// Now getting a different chain so we need to make sure we restart.
void restartGettingChain();
void giveUpOnFetch(); void giveUpOnFetch();
void clearKnownTransactions() { std::lock_guard<std::mutex> l(x_knownTransactions); m_knownTransactions.clear(); }
unsigned m_protocolVersion; unsigned m_protocolVersion;
u256 m_networkId; u256 m_networkId;
Grabbing m_grabbing = Grabbing::State;
h256 m_latestHash; ///< Peer's latest block's hash. h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty. u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer. h256s m_neededBlocks; ///< The blocks that we should download from this peer.
h256Set m_failedBlocks; ///< Blocks that the peer doesn't seem to have.
h256Set m_askedBlocks; ///< The blocks for which we sent the last GetBlocks for but haven't received a corresponding Blocks.
bool m_askedBlocksChanged = true;
bool m_requireTransactions; bool m_requireTransactions;
Mutex x_knownBlocks;
std::set<h256> m_knownBlocks; std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions; std::set<h256> m_knownTransactions;
std::mutex x_knownTransactions;
DownloadSub m_sub;
}; };
} }

1
libethereum/Executive.cpp

@ -187,6 +187,7 @@ bool Executive::go(OnOpFunc const& _onOp)
catch (VMException const& _e) catch (VMException const& _e)
{ {
clog(StateChat) << "VM Exception: " << _e.description(); clog(StateChat) << "VM Exception: " << _e.description();
m_endGas = m_vm->gas();
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {

5
libethereum/Interface.h

@ -95,8 +95,13 @@ public:
virtual bool peekWatch(unsigned _watchId) const = 0; virtual bool peekWatch(unsigned _watchId) const = 0;
virtual bool checkWatch(unsigned _watchId) = 0; virtual bool checkWatch(unsigned _watchId) = 0;
// TODO: Block query API.
// [EXTRA API]: // [EXTRA API]:
/// @returns The height of the chain.
virtual unsigned number() const = 0;
/// Get a map containing each of the pending transactions. /// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions(). /// @TODO: Remove in favour of transactions().
virtual Transactions pending() const = 0; virtual Transactions pending() const = 0;

36
libethereum/Miner.cpp

@ -27,42 +27,12 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
Miner::Miner(MinerHost* _host, unsigned _id): Miner::Miner(MinerHost* _host, unsigned _id):
m_host(_host), Worker("miner-" + toString(_id)),
m_id(_id) m_host(_host)
{ {
} }
void Miner::start() void Miner::doWork()
{
if (!m_host)
return;
Guard l(x_work);
if (!m_work)
{
m_stop = false;
m_work.reset(new thread([&]()
{
setThreadName(("miner-" + toString(m_id)).c_str());
m_miningStatus = Preparing;
while (!m_stop)
work();
}));
}
}
void Miner::stop()
{
Guard l(x_work);
if (m_work)
{
m_stop = true;
m_work->join();
m_work.reset(nullptr);
}
}
void Miner::work()
{ {
// Do some mining. // Do some mining.
if (m_miningStatus != Waiting && m_miningStatus != Mined) if (m_miningStatus != Waiting && m_miningStatus != Mined)

24
libethereum/Miner.h

@ -26,6 +26,7 @@
#include <list> #include <list>
#include <atomic> #include <atomic>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Worker.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include "State.h" #include "State.h"
@ -74,38 +75,38 @@ public:
* @threadsafe * @threadsafe
* @todo Signal Miner to restart once with condition variables. * @todo Signal Miner to restart once with condition variables.
*/ */
class Miner class Miner: Worker
{ {
public: public:
/// Null constructor. /// Null constructor.
Miner(): m_host(nullptr), m_id(0) {} Miner(): m_host(nullptr) {}
/// Constructor. /// Constructor.
Miner(MinerHost* _host, unsigned _id = 0); Miner(MinerHost* _host, unsigned _id = 0);
/// Move-constructor. /// Move-constructor.
Miner(Miner&& _m) { std::swap(m_host, _m.m_host); std::swap(m_id, _m.m_id); } Miner(Miner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
/// Move-assignment. /// Move-assignment.
Miner& operator=(Miner&& _m) { std::swap(m_host, _m.m_host); std::swap(m_id, _m.m_id); return *this; } Miner& operator=(Miner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
/// Destructor. Stops miner. /// Destructor. Stops miner.
~Miner() { stop(); } ~Miner() { stop(); }
/// Setup its basics. /// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; } void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; setName("miner-" + toString(_id)); }
/// Start mining. /// Start mining.
void start(); void start() { startWorking(); }
/// Stop mining. /// Stop mining.
void stop(); void stop() { stopWorking(); }
/// Call to notify Miner of a state change. /// Call to notify Miner of a state change.
void noteStateChange() { m_miningStatus = Preparing; } void noteStateChange() { m_miningStatus = Preparing; }
/// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force().
bool isRunning() { return !!m_work; } bool isRunning() { return isWorking(); }
/// @returns true if mining is complete. /// @returns true if mining is complete.
bool isComplete() const { return m_miningStatus == Mined; } bool isComplete() const { return m_miningStatus == Mined; }
@ -121,14 +122,9 @@ public:
private: private:
/// Do some work on the mining. /// Do some work on the mining.
void work(); virtual void doWork();
MinerHost* m_host = nullptr; ///< Our host. MinerHost* m_host = nullptr; ///< Our host.
unsigned m_id = 0; ///< Our identity.
std::mutex x_work; ///< Mutex protecting the creation of the work thread.
std::unique_ptr<std::thread> m_work; ///< The work thread.
bool m_stop = false; ///< Stop working?
enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped }; enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped };
MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable. MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable.

5
libethereum/State.cpp

@ -152,10 +152,15 @@ State& State::operator=(State const& _s)
m_currentBlock = _s.m_currentBlock; m_currentBlock = _s.m_currentBlock;
m_ourAddress = _s.m_ourAddress; m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward; m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true); paranoia("after state cloning (assignment op)", true);
return *this; return *this;
} }
State::~State()
{
}
struct CachedAddressState struct CachedAddressState
{ {
CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {} CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {}

2
libethereum/State.h

@ -90,6 +90,8 @@ public:
/// Copy state object. /// Copy state object.
State& operator=(State const& _s); State& operator=(State const& _s);
~State();
/// Set the coinbase address for any transactions we do. /// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block. /// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); } void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }

2
libethereum/TransactionQueue.h

@ -52,6 +52,8 @@ public:
void setFuture(std::pair<h256, bytes> const& _t); void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t); void noteGood(std::pair<h256, bytes> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
private: private:
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets. std::set<h256> m_known; ///< Hashes of transactions in both sets.

7
libevm/VM.h

@ -41,7 +41,6 @@ class BreakPointHit: public VMException {};
class BadInstruction: public VMException {}; class BadInstruction: public VMException {};
class OutOfGas: public VMException {}; class OutOfGas: public VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. // Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the right (low-order in BE) 160-bits. // Currently we just pull out the right (low-order in BE) 160-bits.
@ -157,7 +156,11 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
require(3); require(3);
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
break; break;
case Instruction::EXTCODECOPY:
require(4);
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
break;
case Instruction::BALANCE: case Instruction::BALANCE:
runGas = c_balanceGas; runGas = c_balanceGas;
break; break;

261
libevmface/Instruction.h

@ -32,143 +32,140 @@ namespace dev
namespace eth namespace eth
{ {
// TODO: Update comments.
/// Virtual machine bytecode instruction. /// Virtual machine bytecode instruction.
enum class Instruction: uint8_t enum class Instruction: uint8_t
{ {
STOP = 0x00, ///< halts execution STOP = 0x00, ///< halts execution
ADD, ADD, ///< addition operation
MUL, MUL, ///< mulitplication operation
SUB, SUB, ///< subtraction operation
DIV, DIV, ///< integer division operation
SDIV, SDIV, ///< signed integer division operation
MOD, MOD, ///< modulo remainder operation
SMOD, SMOD, ///< signed modulo remainder operation
EXP, EXP, ///< exponential operation
NEG, NEG, ///< negation operation
LT, LT, ///< less-than comparision
GT, GT, ///< greater-than comparision
SLT, SLT, ///< signed less-than comparision
SGT, SGT, ///< signed greater-than comparision
EQ, EQ, ///< equality comparision
NOT, NOT, ///< simple not operator
AND = 0x10, AND = 0x10, ///< bitwise AND operation
OR, OR, ///< bitwise OR operation
XOR, XOR, ///< bitwise XOR operation
BYTE, BYTE, ///< retrieve single byte from word
ADDMOD, ADDMOD, ///< unsigned modular addition
MULMOD, MULMOD, ///< unsigned modular multiplication
SHA3 = 0x20, ///< compute SHA3-256 hash
SHA3 = 0x20,
ADDRESS = 0x30, ///< get address of currently executing account
ADDRESS = 0x30, BALANCE, ///< get balance of the given account
BALANCE, ORIGIN, ///< get execution origination address
ORIGIN, CALLER, ///< get caller address
CALLER, CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution
CALLVALUE, CALLDATALOAD, ///< get input data of current environment
CALLDATALOAD, CALLDATASIZE, ///< get size of input data in current environment
CALLDATASIZE, CALLDATACOPY, ///< copy input data in current environment to memory
CALLDATACOPY, CODESIZE, ///< get size of code running in current environment
CODESIZE, CODECOPY, ///< copy code running in current environment to memory
CODECOPY, GASPRICE, ///< get price of gas in current environment
GASPRICE, EXTCODESIZE, ///< get external code size (from another contract)
EXTCODESIZE, EXTCODECOPY, ///< copy external code (from another contract)
EXTCODECOPY,
PREVHASH = 0x40, ///< get hash of most recent complete block
PREVHASH = 0x40, COINBASE, ///< get the block's coinbase address
COINBASE, TIMESTAMP, ///< get the block's timestamp
TIMESTAMP, NUMBER, ///< get the block's number
NUMBER, DIFFICULTY, ///< get the block's difficulty
DIFFICULTY, GASLIMIT, ///< get the block's gas limit
GASLIMIT,
POP = 0x50, ///< remove item from stack
POP = 0x50, MLOAD = 0x53, ///< load word from memory
MLOAD = 0x53, MSTORE, ///< save word to memory
MSTORE, MSTORE8, ///< save byte to memory
MSTORE8, SLOAD, ///< load word from storage
SLOAD, SSTORE, ///< save word to storage
SSTORE, JUMP, ///< alter the program counter
JUMP, JUMPI, ///< conditionally alter the program counter
JUMPI, PC, ///< get the program counter
PC, MSIZE, ///< get the size of active memory
MSIZE, GAS, ///< get the amount of available gas
GAS,
PUSH1 = 0x60, ///< place 1 byte item on stack
PUSH1 = 0x60, PUSH2, ///< place 2 byte item on stack
PUSH2, PUSH3, ///< place 3 byte item on stack
PUSH3, PUSH4, ///< place 4 byte item on stack
PUSH4, PUSH5, ///< place 5 byte item on stack
PUSH5, PUSH6, ///< place 6 byte item on stack
PUSH6, PUSH7, ///< place 7 byte item on stack
PUSH7, PUSH8, ///< place 8 byte item on stack
PUSH8, PUSH9, ///< place 9 byte item on stack
PUSH9, PUSH10, ///< place 10 byte item on stack
PUSH10, PUSH11, ///< place 11 byte item on stack
PUSH11, PUSH12, ///< place 12 byte item on stack
PUSH12, PUSH13, ///< place 13 byte item on stack
PUSH13, PUSH14, ///< place 14 byte item on stack
PUSH14, PUSH15, ///< place 15 byte item on stack
PUSH15, PUSH16, ///< place 16 byte item on stack
PUSH16, PUSH17, ///< place 17 byte item on stack
PUSH17, PUSH18, ///< place 18 byte item on stack
PUSH18, PUSH19, ///< place 19 byte item on stack
PUSH19, PUSH20, ///< place 20 byte item on stack
PUSH20, PUSH21, ///< place 21 byte item on stack
PUSH21, PUSH22, ///< place 22 byte item on stack
PUSH22, PUSH23, ///< place 23 byte item on stack
PUSH23, PUSH24, ///< place 24 byte item on stack
PUSH24, PUSH25, ///< place 25 byte item on stack
PUSH25, PUSH26, ///< place 26 byte item on stack
PUSH26, PUSH27, ///< place 27 byte item on stack
PUSH27, PUSH28, ///< place 28 byte item on stack
PUSH28, PUSH29, ///< place 29 byte item on stack
PUSH29, PUSH30, ///< place 30 byte item on stack
PUSH30, PUSH31, ///< place 31 byte item on stack
PUSH31, PUSH32, ///< place 32 byte item on stack
PUSH32,
DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack
DUP1 = 0x80, DUP2, ///< copies the second highest item in the stack to the top of the stack
DUP2, DUP3, ///< copies the third highest item in the stack to the top of the stack
DUP3, DUP4, ///< copies the 4th highest item in the stack to the top of the stack
DUP4, DUP5, ///< copies the 5th highest item in the stack to the top of the stack
DUP5, DUP6, ///< copies the 6th highest item in the stack to the top of the stack
DUP6, DUP7, ///< copies the 7th highest item in the stack to the top of the stack
DUP7, DUP8, ///< copies the 8th highest item in the stack to the top of the stack
DUP8, DUP9, ///< copies the 9th highest item in the stack to the top of the stack
DUP9, DUP10, ///< copies the 10th highest item in the stack to the top of the stack
DUP10, DUP11, ///< copies the 11th highest item in the stack to the top of the stack
DUP11, DUP12, ///< copies the 12th highest item in the stack to the top of the stack
DUP12, DUP13, ///< copies the 13th highest item in the stack to the top of the stack
DUP13, DUP14, ///< copies the 14th highest item in the stack to the top of the stack
DUP14, DUP15, ///< copies the 15th highest item in the stack to the top of the stack
DUP15, DUP16, ///< copies the 16th highest item in the stack to the top of the stack
DUP16,
SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack
SWAP1 = 0x90, SWAP2, ///< swaps the highest and third highest value on the stack
SWAP2, SWAP3, ///< swaps the highest and 4th highest value on the stack
SWAP3, SWAP4, ///< swaps the highest and 5th highest value on the stack
SWAP4, SWAP5, ///< swaps the highest and 6th highest value on the stack
SWAP5, SWAP6, ///< swaps the highest and 7th highest value on the stack
SWAP6, SWAP7, ///< swaps the highest and 8th highest value on the stack
SWAP7, SWAP8, ///< swaps the highest and 9th highest value on the stack
SWAP8, SWAP9, ///< swaps the highest and 10th highest value on the stack
SWAP9, SWAP10, ///< swaps the highest and 11th highest value on the stack
SWAP10, SWAP11, ///< swaps the highest and 12th highest value on the stack
SWAP11, SWAP12, ///< swaps the highest and 13th highest value on the stack
SWAP12, SWAP13, ///< swaps the highest and 14th highest value on the stack
SWAP13, SWAP14, ///< swaps the highest and 15th highest value on the stack
SWAP14, SWAP15, ///< swaps the highest and 16th highest value on the stack
SWAP15, SWAP16, ///< swaps the highest and 17th highest value on the stack
SWAP16,
CREATE = 0xf0, ///< create a new account with associated code
CREATE = 0xf0, CALL, ///< message-call into an account
CALL, RETURN, ///< halt execution returning output data
RETURN, POST, ///< asynchronous call without output (adds a message to the post queue)
POST,
CALLSTATELESS, CALLSTATELESS,
SUICIDE = 0xff SUICIDE = 0xff ///< halt execution and register account for later deletion
}; };
/// Information structure for a particular instruction. /// Information structure for a particular instruction.

1
libp2p/Common.h

@ -94,6 +94,7 @@ struct PeerInfo
std::string host; std::string host;
unsigned short port; unsigned short port;
std::chrono::steady_clock::duration lastPing; std::chrono::steady_clock::duration lastPing;
std::set<std::string> caps;
}; };
} }

151
libp2p/Host.cpp

@ -17,7 +17,7 @@
/** @file Host.cpp /** @file Host.cpp
* @authors: * @authors:
* Gav Wood <i@gavwood.com> * Gav Wood <i@gavwood.com>
* Eric Lombrozo <elombrozo@gmail.com> * Eric Lombrozo <elombrozo@gmail.com> (Windows version of populateAddresses())
* @date 2014 * @date 2014
*/ */
@ -34,6 +34,7 @@
#include <set> #include <set>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include "Session.h" #include "Session.h"
@ -54,55 +55,89 @@ static const set<bi::address> c_rejectAddresses = {
{bi::address_v6::from_string("::")} {bi::address_v6::from_string("::")}
}; };
Host::Host(std::string const& _clientVersion, unsigned short _port, string const& _publicAddress, bool _upnp, bool _localNetworking): Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start):
Worker("p2p"),
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_listenPort(_port), m_netPrefs(_n),
m_localNetworking(_localNetworking), m_acceptor(m_ioService),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService), m_socket(m_ioService),
m_id(h512::random()) m_id(h512::random())
{ {
populateAddresses(); populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
m_lastPeersRequest = chrono::steady_clock::time_point::min(); m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << m_id.abridged(); clog(NetNote) << "Id:" << m_id.abridged();
if (_start)
start();
} }
Host::Host(std::string const& _clientVersion, string const& _publicAddress, bool _upnp, bool _localNetworking): Host::~Host()
m_clientVersion(_clientVersion),
m_listenPort(0),
m_localNetworking(_localNetworking),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_id(h512::random())
{ {
m_listenPort = m_acceptor.local_endpoint().port(); stop();
// populate addresses.
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << m_id.abridged();
} }
Host::Host(std::string const& _clientVersion): void Host::start()
m_clientVersion(_clientVersion),
m_listenPort(0),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_id(h512::random())
{ {
// populate addresses. if (isWorking())
populateAddresses(); stop();
for (unsigned i = 0; i < 2; ++i)
{
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort);
try
{
m_acceptor.open(endpoint.protocol());
m_acceptor.set_option(ba::socket_base::reuse_address(true));
m_acceptor.bind(endpoint);
m_acceptor.listen();
m_listenPort = i ? m_acceptor.local_endpoint().port() : m_netPrefs.listenPort;
break;
}
catch (...)
{
if (i)
{
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?";
return;
}
m_acceptor.close();
continue;
}
}
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
ensureAccepting();
m_incomingPeers.clear();
m_freePeers.clear();
m_lastPeersRequest = chrono::steady_clock::time_point::min(); m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << m_id.abridged(); clog(NetNote) << "Id:" << m_id.abridged();
for (auto const& h: m_capabilities)
h.second->onStarting();
startWorking();
} }
Host::~Host() void Host::stop()
{ {
for (auto const& h: m_capabilities)
h.second->onStopping();
stopWorking();
if (m_acceptor.is_open())
{
if (m_accepting)
m_acceptor.cancel();
m_acceptor.close();
m_accepting = false;
}
if (m_socket.is_open())
m_socket.close();
disconnectPeers(); disconnectPeers();
m_ioService.reset();
} }
unsigned Host::protocolVersion() const unsigned Host::protocolVersion() const
@ -283,8 +318,14 @@ std::map<h512, bi::tcp::endpoint> Host::potentialPeers()
if (auto j = i.second.lock()) if (auto j = i.second.lock())
{ {
auto ep = j->endpoint(); auto ep = j->endpoint();
// cnote << "Checking potential peer" << j->m_listenPort << j->endpoint() << isPrivateAddress(ep.address()) << ep.port() << j->m_id.abridged();
// Skip peers with a listen port of zero or are on a private network // Skip peers with a listen port of zero or are on a private network
bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_localNetworking)); bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
if (!peerOnNet && m_incomingPeers.count(j->m_id))
{
ep = m_incomingPeers.at(j->m_id).first;
peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
}
if (peerOnNet && ep.port() && j->m_id) if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep)); ret.insert(make_pair(i.first, ep));
} }
@ -293,7 +334,7 @@ std::map<h512, bi::tcp::endpoint> Host::potentialPeers()
void Host::ensureAccepting() void Host::ensureAccepting()
{ {
if (m_accepting == false) if (!m_accepting)
{ {
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")"; clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true; m_accepting = true;
@ -315,23 +356,38 @@ void Host::ensureAccepting()
clog(NetWarn) << "ERROR: " << _e.what(); clog(NetWarn) << "ERROR: " << _e.what();
} }
m_accepting = false; m_accepting = false;
if (ec.value() != 1) if (ec.value() < 1)
ensureAccepting(); ensureAccepting();
}); });
} }
} }
string Host::pocHost()
{
vector<string> strs;
boost::split(strs, dev::Version, boost::is_any_of("."));
return "poc-" + strs[1] + ".ethdev.com";
}
void Host::connect(std::string const& _addr, unsigned short _port) noexcept void Host::connect(std::string const& _addr, unsigned short _port) noexcept
{ {
try for (int i = 0; i < 2; ++i)
{ try
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port)); {
} if (i == 0)
catch (exception const& e) {
{ bi::tcp::resolver r(m_ioService);
// Couldn't connect connect(r.resolve({_addr, toString(_port)})->endpoint());
clog(NetConnect) << "Bad host " << _addr << " (" << e.what() << ")"; }
} else
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port));
break;
}
catch (exception const& e)
{
// Couldn't connect
clog(NetConnect) << "Bad host " << _addr << " (" << e.what() << ")";
}
} }
void Host::connect(bi::tcp::endpoint const& _ep) void Host::connect(bi::tcp::endpoint const& _ep)
@ -397,7 +453,6 @@ void Host::growPeers()
m_lastPeersRequest = chrono::steady_clock::now(); m_lastPeersRequest = chrono::steady_clock::now();
} }
if (!m_accepting) if (!m_accepting)
ensureAccepting(); ensureAccepting();
@ -406,7 +461,8 @@ void Host::growPeers()
auto x = time(0) % m_freePeers.size(); auto x = time(0) % m_freePeers.size();
m_incomingPeers[m_freePeers[x]].second++; m_incomingPeers[m_freePeers[x]].second++;
connect(m_incomingPeers[m_freePeers[x]].first); if (!m_peers.count(m_freePeers[x]))
connect(m_incomingPeers[m_freePeers[x]].first);
m_freePeers.erase(m_freePeers.begin() + x); m_freePeers.erase(m_freePeers.begin() + x);
} }
} }
@ -457,11 +513,8 @@ std::vector<PeerInfo> Host::peers(bool _updatePing) const
return ret; return ret;
} }
void Host::process() void Host::doWork()
{ {
for (auto const& i: m_capabilities)
if (!i.second->isInitialised())
return;
growPeers(); growPeers();
prunePeers(); prunePeers();
m_ioService.poll(); m_ioService.poll();

44
libp2p/Host.h

@ -29,6 +29,7 @@
#include <utility> #include <utility>
#include <thread> #include <thread>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include "HostCapability.h" #include "HostCapability.h"
namespace ba = boost::asio; namespace ba = boost::asio;
namespace bi = boost::asio::ip; namespace bi = boost::asio::ip;
@ -41,22 +42,28 @@ class RLPStream;
namespace p2p namespace p2p
{ {
struct NetworkPreferences
{
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {}
unsigned short listenPort = 30303;
std::string publicIP;
bool upnp = true;
bool localNetworking = false;
};
/** /**
* @brief The Host class * @brief The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
*/ */
class Host class Host: public Worker
{ {
friend class Session; friend class Session;
friend class HostCapabilityFace; friend class HostCapabilityFace;
public: public:
/// Start server, listening for connections on the given port. /// Start server, listening for connections on the given port.
Host(std::string const& _clientVersion, unsigned short _port, std::string const& _publicAddress = std::string(), bool _upnp = true, bool _localNetworking = false); Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false);
/// Start server, listening for connections on a system-assigned port.
Host(std::string const& _clientVersion, std::string const& _publicAddress = std::string(), bool _upnp = true, bool _localNetworking = false);
/// Start server, but don't listen.
Host(std::string const& _clientVersion);
/// Will block on network process events. /// Will block on network process events.
virtual ~Host(); virtual ~Host();
@ -75,14 +82,10 @@ public:
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(T::staticName())); } catch (...) { return nullptr; } } template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(T::staticName())); } catch (...) { return nullptr; } }
/// Connect to a peer explicitly. /// Connect to a peer explicitly.
static std::string pocHost();
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept; void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep); void connect(bi::tcp::endpoint const& _ep);
/// 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();
/// @returns true iff we have the a peer of the given id. /// @returns true iff we have the a peer of the given id.
bool havePeer(h512 _id) const; bool havePeer(h512 _id) const;
@ -107,11 +110,17 @@ public:
/// Deserialise the data and populate the set of known peers. /// Deserialise the data and populate the set of known peers.
void restorePeers(bytesConstRef _b); void restorePeers(bytesConstRef _b);
void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); }
void start();
void stop();
bool isStarted() const { return isWorking(); }
h512 id() const { return m_id; } h512 id() const { return m_id; }
void registerPeer(std::shared_ptr<Session> _s, std::vector<std::string> const& _caps); void registerPeer(std::shared_ptr<Session> _s, std::vector<std::string> const& _caps);
protected: private:
/// Called when the session has provided us with a new peer we can connect to. /// Called when the session has provided us with a new peer we can connect to.
void noteNewPeers() {} void noteNewPeers() {}
@ -123,12 +132,19 @@ protected:
void growPeers(); void growPeers();
void prunePeers(); void prunePeers();
/// 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.
virtual void doWork();
std::map<h512, bi::tcp::endpoint> potentialPeers(); std::map<h512, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion; std::string m_clientVersion;
unsigned short m_listenPort; NetworkPreferences m_netPrefs;
bool m_localNetworking = false;
static const int NetworkStopped = -1;
int m_listenPort = NetworkStopped;
ba::io_service m_ioService; ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor; bi::tcp::acceptor m_acceptor;

4
libp2p/HostCapability.h

@ -48,7 +48,9 @@ public:
protected: protected:
virtual std::string name() const = 0; virtual std::string name() const = 0;
virtual Capability* newPeerCapability(Session* _s) = 0; virtual Capability* newPeerCapability(Session* _s) = 0;
virtual bool isInitialised() const { return true; }
virtual void onStarting() {}
virtual void onStopping() {}
void seal(bytes& _b); void seal(bytes& _b);

34
libp2p/Session.cpp

@ -102,7 +102,7 @@ bool Session::interpret(RLP const& _r)
return false; return false;
} }
try try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration()}); } { m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration(), _r[3].toSet<string>()}); }
catch (...) catch (...)
{ {
disconnect(BadProtocol); disconnect(BadProtocol);
@ -159,13 +159,13 @@ bool Session::interpret(RLP const& _r)
bi::address_v4 peerAddress(_r[i][0].toHash<FixedHash<4>>().asArray()); bi::address_v4 peerAddress(_r[i][0].toHash<FixedHash<4>>().asArray());
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>()); auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>());
h512 id = _r[i][2].toHash<h512>(); h512 id = _r[i][2].toHash<h512>();
if (isPrivateAddress(peerAddress) && !m_server->m_localNetworking) clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << m_id.abridged() << isPrivateAddress(endpoint().address()) << m_server->m_incomingPeers.count(id) << (m_server->m_incomingPeers.count(id) ? isPrivateAddress(m_server->m_incomingPeers.at(id).first.address()) : -1);
goto CONTINUE;
clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; if (isPrivateAddress(peerAddress) && !m_server->m_netPrefs.localNetworking)
goto CONTINUE;
// check that it's not us or one we already know: // check that it's not us or one we already know:
if (id && (m_server->m_id == id || m_server->havePeer(id) || m_server->m_incomingPeers.count(id))) if (!(m_id == id && isPrivateAddress(endpoint().address()) && (!m_server->m_incomingPeers.count(id) || isPrivateAddress(m_server->m_incomingPeers.at(id).first.address()))) && (!id || m_server->m_id == id || m_server->m_incomingPeers.count(id)))
goto CONTINUE; goto CONTINUE;
// check that we're not already connected to addr: // check that we're not already connected to addr:
@ -180,7 +180,7 @@ bool Session::interpret(RLP const& _r)
m_server->m_incomingPeers[id] = make_pair(ep, 0); m_server->m_incomingPeers[id] = make_pair(ep, 0);
m_server->m_freePeers.push_back(id); m_server->m_freePeers.push_back(id);
m_server->noteNewPeers(); m_server->noteNewPeers();
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id << ")"; clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:; CONTINUE:;
} }
break; break;
@ -266,19 +266,19 @@ void Session::writeImpl(bytes& _buffer)
if (!m_socket.is_open()) if (!m_socket.is_open())
return; return;
lock_guard<recursive_mutex> l(m_writeLock); bool doWrite = false;
m_writeQueue.push_back(_buffer); {
if (m_writeQueue.size() == 1) lock_guard<mutex> l(m_writeLock);
m_writeQueue.push_back(_buffer);
doWrite = (m_writeQueue.size() == 1);
}
if (doWrite)
write(); write();
} }
void Session::write() void Session::write()
{ {
// cerr << (void*)this << " write" << endl;
lock_guard<recursive_mutex> l(m_writeLock);
if (m_writeQueue.empty())
return;
const bytes& bytes = m_writeQueue[0]; const bytes& bytes = m_writeQueue[0];
auto self(shared_from_this()); auto self(shared_from_this());
ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/) ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/)
@ -290,12 +290,16 @@ void Session::write()
{ {
cwarn << "Error sending: " << ec.message(); cwarn << "Error sending: " << ec.message();
dropped(); dropped();
return;
} }
else else
{ {
lock_guard<mutex> l(m_writeLock);
m_writeQueue.pop_front(); m_writeQueue.pop_front();
write(); if (m_writeQueue.empty())
return;
} }
write();
}); });
} }

2
libp2p/Session.h

@ -86,7 +86,7 @@ private:
Host* m_server; Host* m_server;
std::recursive_mutex m_writeLock; std::mutex m_writeLock;
std::deque<bytes> m_writeQueue; std::deque<bytes> m_writeQueue;
mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle(). mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().

2
libqethereum/CMakeLists.txt

@ -105,6 +105,6 @@ else ()
target_link_libraries(${EXECUTABLE} boost_filesystem) target_link_libraries(${EXECUTABLE} boost_filesystem)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
endif () endif ()

53
libqethereum/QEthereum.cpp

@ -8,41 +8,8 @@
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include "QEthereum.h" #include "QEthereum.h"
using namespace std; using namespace std;
using namespace dev;
// types using namespace dev::eth;
using dev::bytes;
using dev::bytesConstRef;
using dev::h160;
using dev::h256;
using dev::u160;
using dev::u256;
using dev::u256s;
using dev::RLP;
using dev::Address;
using dev::eth::BlockInfo;
using dev::eth::Client;
using dev::eth::Instruction;
using dev::KeyPair;
using dev::eth::NodeMode;
using dev::p2p::PeerInfo;
using dev::Secret;
using dev::eth::Transaction;
// functions
using dev::toHex;
using dev::fromHex;
using dev::right160;
using dev::simpleDebugOut;
using dev::toLog2;
using dev::toString;
using dev::operator+;
using dev::eth::disassemble;
using dev::eth::units;
using dev::eth::formatBalance;
// vars
using dev::g_logPost;
using dev::g_logVerbosity;
dev::bytes toBytes(QString const& _s) dev::bytes toBytes(QString const& _s)
{ {
@ -89,7 +56,7 @@ QString unpadded(QString _s)
return _s; return _s;
} }
QEthereum::QEthereum(QObject* _p, Client* _c, QList<dev::KeyPair> _accounts): QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList<dev::KeyPair> _accounts):
QObject(_p), m_client(_c), m_accounts(_accounts) QObject(_p), m_client(_c), m_accounts(_accounts)
{ {
// required to prevent crash on osx when performing addto/evaluatejavascript calls // required to prevent crash on osx when performing addto/evaluatejavascript calls
@ -120,7 +87,7 @@ QString QEthereum::secretToAddress(QString _s) const
return toQJS(KeyPair(toSecret(_s)).address()); return toQJS(KeyPair(toSecret(_s)).address());
} }
Client* QEthereum::client() const eth::Interface* QEthereum::client() const
{ {
return m_client; return m_client;
} }
@ -162,7 +129,7 @@ QString QEthereum::coinbase() const
QString QEthereum::number() const QString QEthereum::number() const
{ {
return m_client ? QString::number(client()->blockChain().number() + 1) : ""; return m_client ? QString::number(client()->number() + 1) : "";
} }
QString QEthereum::account() const QString QEthereum::account() const
@ -381,7 +348,7 @@ bool QEthereum::isMining() const
bool QEthereum::isListening() const bool QEthereum::isListening() const
{ {
return m_client ? client()->haveNetwork() : false; return /*m_client ? client()->haveNetwork() :*/ false;
} }
void QEthereum::setMining(bool _l) void QEthereum::setMining(bool _l)
@ -395,19 +362,19 @@ void QEthereum::setMining(bool _l)
} }
} }
void QEthereum::setListening(bool _l) void QEthereum::setListening(bool)
{ {
if (!m_client) if (!m_client)
return; return;
if (_l) /* if (_l)
client()->startNetwork(); client()->startNetwork();
else else
client()->stopNetwork(); client()->stopNetwork();*/
} }
unsigned QEthereum::peerCount() const unsigned QEthereum::peerCount() const
{ {
return m_client ? (unsigned)client()->peerCount() : 0; return /*m_client ? (unsigned)client()->peerCount() :*/ 0;
} }
QString QEthereum::doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice) QString QEthereum::doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice)

11
libqethereum/QEthereum.h

@ -7,8 +7,7 @@
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
namespace dev { namespace eth { namespace dev { namespace eth {
class Client; class Interface;
class State;
}} }}
class QJSEngine; class QJSEngine;
@ -99,11 +98,11 @@ class QEthereum: public QObject
Q_OBJECT Q_OBJECT
public: public:
QEthereum(QObject* _p, dev::eth::Client* _c, QList<dev::KeyPair> _accounts); QEthereum(QObject* _p, dev::eth::Interface* _c, QList<dev::KeyPair> _accounts);
virtual ~QEthereum(); virtual ~QEthereum();
dev::eth::Client* client() const; dev::eth::Interface* client() const;
void setClient(dev::eth::Client* _c) { m_client = _c; } void setClient(dev::eth::Interface* _c) { m_client = _c; }
/// Call when the client() is going to be deleted to make this object useless but safe. /// Call when the client() is going to be deleted to make this object useless but safe.
void clientDieing(); void clientDieing();
@ -199,7 +198,7 @@ private:
Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged) Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged)
Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault) Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault)
dev::eth::Client* m_client; dev::eth::Interface* m_client;
std::vector<unsigned> m_watches; std::vector<unsigned> m_watches;
QList<dev::KeyPair> m_accounts; QList<dev::KeyPair> m_accounts;
}; };

4
libqethereum/QmlEthereum.cpp

@ -50,7 +50,7 @@ using dev::g_logVerbosity;
// Can get rid of this once we've sorted out ITC for signalling & multiplexed querying. // Can get rid of this once we've sorted out ITC for signalling & multiplexed querying.
dev::eth::Client* g_qmlClient; dev::eth::Client* g_qmlClient;
QObject* g_qmlMain; QObject* g_qmlMain;
#if 0
QmlAccount::QmlAccount(QObject*) QmlAccount::QmlAccount(QObject*)
{ {
} }
@ -177,6 +177,8 @@ void QmlEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _ga
client()->transact(_secret, _amount, _dest, bytes(_data.data(), _data.data() + _data.size()), _gas, _gasPrice); client()->transact(_secret, _amount, _dest, bytes(_data.data(), _data.data() + _data.size()), _gas, _gasPrice);
} }
#endif
// extra bits needed to link on VS // extra bits needed to link on VS
#ifdef _MSC_VER #ifdef _MSC_VER

8
libqethereum/QmlEthereum.h

@ -23,8 +23,8 @@ Q_DECLARE_METATYPE(dev::u256)
Q_DECLARE_METATYPE(dev::Address) Q_DECLARE_METATYPE(dev::Address)
Q_DECLARE_METATYPE(dev::Secret) Q_DECLARE_METATYPE(dev::Secret)
Q_DECLARE_METATYPE(dev::KeyPair) Q_DECLARE_METATYPE(dev::KeyPair)
Q_DECLARE_METATYPE(QmlAccount*) //Q_DECLARE_METATYPE(QmlAccount*)
Q_DECLARE_METATYPE(QmlEthereum*) //Q_DECLARE_METATYPE(QmlEthereum*)
class QmlU256Helper: public QObject class QmlU256Helper: public QObject
{ {
@ -75,7 +75,7 @@ public:
Q_INVOKABLE QString stringOf(dev::Address _a) const { return QString::fromStdString(dev::toHex(_a.asArray())); } Q_INVOKABLE QString stringOf(dev::Address _a) const { return QString::fromStdString(dev::toHex(_a.asArray())); }
Q_INVOKABLE QString toAbridged(dev::Address _a) const { return QString::fromStdString(_a.abridged()); } Q_INVOKABLE QString toAbridged(dev::Address _a) const { return QString::fromStdString(_a.abridged()); }
}; };
#if 0
class QmlAccount: public QObject class QmlAccount: public QObject
{ {
Q_OBJECT Q_OBJECT
@ -155,7 +155,7 @@ private:
Q_PROPERTY(bool listening READ isListening WRITE setListening) Q_PROPERTY(bool listening READ isListening WRITE setListening)
Q_PROPERTY(bool mining READ isMining WRITE setMining) Q_PROPERTY(bool mining READ isMining WRITE setMining)
}; };
#endif
#if 0 #if 0
template <class T> T to(QVariant const& _s) { if (_s.type() != QVariant::String) return T(); auto s = _s.toString().toLatin1(); assert(s.size() == sizeof(T)); return *(T*)s.data(); } template <class T> T to(QVariant const& _s) { if (_s.type() != QVariant::String) return T(); auto s = _s.toString().toLatin1(); assert(s.size() == sizeof(T)); return *(T*)s.data(); }
template <class T> QVariant toQJS(T const& _s) { QLatin1String ret((char*)&_s, sizeof(T)); assert(QVariant(QString(ret)).toString().toLatin1().size() == sizeof(T)); assert(*(T*)(QVariant(QString(ret)).toString().toLatin1().data()) == _s); return QVariant(QString(ret)); } template <class T> QVariant toQJS(T const& _s) { QLatin1String ret((char*)&_s, sizeof(T)); assert(QVariant(QString(ret)).toString().toLatin1().size() == sizeof(T)); assert(*(T*)(QVariant(QString(ret)).toString().toLatin1().data()) == _s); return QVariant(QString(ret)); }

58
libwebthree/WebThree.cpp

@ -35,102 +35,50 @@ using namespace dev::p2p;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::shh; using namespace dev::shh;
WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set<std::string> const& _interfaces, unsigned short _listenPort, std::string const& _publicIP, bool _upnp, dev::u256 _networkId, bool _localNetworking): WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set<std::string> const& _interfaces, NetworkPreferences const& _n):
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_net(m_clientVersion, _listenPort, _publicIP, _upnp, _localNetworking) m_net(_clientVersion, _n)
{ {
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
if (_interfaces.count("eth")) if (_interfaces.count("eth"))
m_ethereum.reset(new eth::Client(&m_net, _dbPath, _forceClean, _networkId)); m_ethereum.reset(new eth::Client(&m_net, _dbPath, _forceClean));
// if (_interfaces.count("shh")) // if (_interfaces.count("shh"))
// m_whisper = new eth::Whisper(m_net.get()); // m_whisper = new eth::Whisper(m_net.get());
static const char* c_threadName = "net";
UpgradableGuard l(x_work);
{
UpgradeGuard ul(l);
if (!m_work)
m_work.reset(new thread([&]()
{
setThreadName(c_threadName);
m_workState.store(Active, std::memory_order_release);
while (m_workState.load(std::memory_order_acquire) != Deleting)
workNet();
m_workState.store(Deleted, std::memory_order_release);
}));
}
} }
WebThreeDirect::~WebThreeDirect() WebThreeDirect::~WebThreeDirect()
{ {
UpgradableGuard l(x_work);
if (m_work)
{
if (m_workState.load(std::memory_order_acquire) == Active)
m_workState.store(Deleting, std::memory_order_release);
while (m_workState.load(std::memory_order_acquire) != Deleted)
this_thread::sleep_for(chrono::milliseconds(10));
m_work->join();
}
if (m_work)
{
UpgradeGuard ul(l);
m_work.reset(nullptr);
}
} }
std::vector<PeerInfo> WebThreeDirect::peers() std::vector<PeerInfo> WebThreeDirect::peers()
{ {
ReadGuard l(x_work);
return m_net.peers(); return m_net.peers();
} }
size_t WebThreeDirect::peerCount() const size_t WebThreeDirect::peerCount() const
{ {
ReadGuard l(x_work);
return m_net.peerCount(); return m_net.peerCount();
} }
void WebThreeDirect::setIdealPeerCount(size_t _n) void WebThreeDirect::setIdealPeerCount(size_t _n)
{ {
ReadGuard l(x_work);
return m_net.setIdealPeerCount(_n); return m_net.setIdealPeerCount(_n);
} }
bytes WebThreeDirect::savePeers() bytes WebThreeDirect::savePeers()
{ {
ReadGuard l(x_work);
return m_net.savePeers(); return m_net.savePeers();
} }
void WebThreeDirect::restorePeers(bytesConstRef _saved) void WebThreeDirect::restorePeers(bytesConstRef _saved)
{ {
ReadGuard l(x_work);
return m_net.restorePeers(_saved); return m_net.restorePeers(_saved);
} }
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port) void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)
{ {
ReadGuard l(x_work);
m_net.connect(_seedHost, _port); m_net.connect(_seedHost, _port);
} }
void WebThreeDirect::workNet()
{
// Process network events.
// Synchronise block chain with network.
// Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks.
{
ReadGuard l(x_work);
m_net.process(); // must be in guard for now since it uses the blockchain.
}
this_thread::sleep_for(chrono::milliseconds(1));
}

24
libwebthree/WebThree.h

@ -66,7 +66,7 @@ class WebThreeDirect
public: public:
/// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception. /// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception.
/// ethereum() may be safely static_cast()ed to a eth::Client*. /// ethereum() may be safely static_cast()ed to a eth::Client*.
WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set<std::string> const& _interfaces = {"eth", "shh"}, unsigned short _listenPort = 30303, std::string const& _publicIP = std::string(), bool _upnp = true, dev::u256 _networkId = 0, bool _localNetworking = false); WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set<std::string> const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences());
/// Destructor. /// Destructor.
~WebThreeDirect(); ~WebThreeDirect();
@ -104,25 +104,23 @@ public:
/// Sets the ideal number of peers. /// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n); void setIdealPeerCount(size_t _n);
bool haveNetwork() const { return m_net.isStarted(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
/// Start the network subsystem. /// Start the network subsystem.
void startNetwork() { setIdealPeerCount(5); } void startNetwork() { m_net.start(); }
/// Stop the network subsystem. /// Stop the network subsystem.
void stopNetwork() { setIdealPeerCount(0); } void stopNetwork() { m_net.stop(); }
private: private:
/// Do some work on the network.
void workNet();
std::string m_clientVersion; ///< Our end-application client's name/version. std::string m_clientVersion; ///< Our end-application client's name/version.
std::unique_ptr<eth::Client> m_ethereum; ///< Main interface for Ethereum ("eth") protocol. std::unique_ptr<eth::Client> m_ethereum; ///< Main interface for Ethereum ("eth") protocol.
std::unique_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol. std::unique_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required. p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::unique_ptr<std::thread> m_work; ///< The network thread.
mutable boost::shared_mutex x_work; ///< Lock for the network existance.
std::atomic<WorkState> m_workState;
}; };
@ -137,7 +135,7 @@ class RPCMaster {};
class EthereumSlave: public eth::Interface class EthereumSlave: public eth::Interface
{ {
public: public:
EthereumSlave(RPCSlave* _c) {} EthereumSlave(RPCSlave*) {}
// TODO: implement all of the virtuals with the RLPClient link. // TODO: implement all of the virtuals with the RLPClient link.
}; };
@ -145,7 +143,7 @@ public:
class EthereumMaster class EthereumMaster
{ {
public: public:
EthereumMaster(RPCMaster* _m) {} EthereumMaster(RPCMaster*) {}
// TODO: implement the master-end of whatever the RLPClient link will send over. // TODO: implement the master-end of whatever the RLPClient link will send over.
}; };
@ -155,7 +153,7 @@ public:
class WhisperSlave: public shh::Interface class WhisperSlave: public shh::Interface
{ {
public: public:
WhisperSlave(RPCSlave* _c) {} WhisperSlave(RPCSlave*) {}
// TODO: implement all of the virtuals with the RLPClient link. // TODO: implement all of the virtuals with the RLPClient link.
}; };
@ -163,7 +161,7 @@ public:
class WhisperMaster class WhisperMaster
{ {
public: public:
WhisperMaster(RPCMaster* _m) {} WhisperMaster(RPCMaster*) {}
// TODO: implement the master-end of whatever the RLPClient link will send over. // TODO: implement the master-end of whatever the RLPClient link will send over.
}; };

2
libwhisper/WhisperPeer.h

@ -95,7 +95,7 @@ class MessageFilter
public: public:
MessageFilter() {} MessageFilter() {}
MessageFilter(std::vector<std::pair<bytes, bytes> > const& _m): m_topicMasks(_m) {} MessageFilter(std::vector<std::pair<bytes, bytes> > const& _m): m_topicMasks(_m) {}
MessageFilter(RLP const& _r): m_topicMasks(_r.operator std::vector<std::pair<bytes, bytes>>()) {} MessageFilter(RLP const& _r): m_topicMasks((std::vector<std::pair<bytes, bytes>>)_r) {}
void fillStream(RLPStream& _s) const { _s << m_topicMasks; } void fillStream(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); } h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); }

1
neth/CMakeLists.txt

@ -11,6 +11,7 @@ set(EXECUTABLE neth)
add_executable(${EXECUTABLE} ${SRC_LIST}) add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp) target_link_libraries(${EXECUTABLE} gmp)

42
neth/main.cpp

@ -39,6 +39,7 @@
#include <eth/CommonJS.h> #include <eth/CommonJS.h>
#include <eth/CommonJS.cpp> #include <eth/CommonJS.cpp>
#endif #endif
#include <libwebthree/WebThree.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#undef KEY_EVENT // from windows.h #undef KEY_EVENT // from windows.h
@ -304,7 +305,6 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
string dbPath; string dbPath;
bool mining = false; bool mining = false;
NodeMode mode = NodeMode::Full;
unsigned peers = 5; unsigned peers = 5;
#if ETH_JSONRPC #if ETH_JSONRPC
int jsonrpc = 8080; int jsonrpc = 8080;
@ -389,19 +389,6 @@ int main(int argc, char** argv)
g_logVerbosity = atoi(argv[++i]); g_logVerbosity = atoi(argv[++i]);
else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
peers = atoi(argv[++i]); peers = atoi(argv[++i]);
else if ((arg == "-o" || arg == "--mode") && i + 1 < argc)
{
string m = argv[++i];
if (m == "full")
mode = NodeMode::Full;
else if (m == "peer")
mode = NodeMode::PeerServer;
else
{
cerr << "Unknown mode: " << m << endl;
return -1;
}
}
else if (arg == "-h" || arg == "--help") else if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
@ -413,7 +400,8 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
Client c("NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath); WebThreeDirect web3("NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath);
Client& c = *web3.ethereum();
c.setForceMining(true); c.setForceMining(true);
@ -479,7 +467,12 @@ int main(int argc, char** argv)
wmove(mainwin, 1, 4); wmove(mainwin, 1, 4);
if (!remoteHost.empty()) if (!remoteHost.empty())
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); {
web3.setIdealPeerCount(peers);
web3.setNetworkPreferences(NetworkPreferences(listenPort, publicIP, upnp));
web3.startNetwork();
web3.connect(remoteHost, remotePort);
}
if (mining) if (mining)
c.startMining(); c.startMining();
@ -487,7 +480,7 @@ int main(int argc, char** argv)
auto_ptr<EthStubServer> jsonrpcServer; auto_ptr<EthStubServer> jsonrpcServer;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us}); jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
@ -528,18 +521,19 @@ int main(int argc, char** argv)
{ {
unsigned port; unsigned port;
iss >> port; iss >> port;
c.startNetwork((short)port); web3.setNetworkPreferences(NetworkPreferences((short)port, publicIP, upnp));
web3.startNetwork();
} }
else if (cmd == "connect") else if (cmd == "connect")
{ {
string addr; string addr;
unsigned port; unsigned port;
iss >> addr >> port; iss >> addr >> port;
c.connect(addr, (short)port); web3.connect(addr, (short)port);
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {
c.stopNetwork(); web3.stopNetwork();
} }
else if (cmd == "minestart") else if (cmd == "minestart")
{ {
@ -560,7 +554,7 @@ int main(int argc, char** argv)
{ {
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = 8080; jsonrpc = 8080;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us}); jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
@ -589,7 +583,7 @@ int main(int argc, char** argv)
} }
else if (cmd == "peers") else if (cmd == "peers")
{ {
for (auto it: c.peers()) for (auto it: web3.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", " cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms" << std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl; << endl;
@ -925,7 +919,7 @@ int main(int argc, char** argv)
// Peers // Peers
y = 1; y = 1;
for (PeerInfo const& i: c.peers()) for (PeerInfo const& i: web3.peers())
{ {
auto s = boost::format("%1% ms - %2%:%3% - %4%") % auto s = boost::format("%1% ms - %2%:%3% - %4%") %
toString(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) % toString(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) %
@ -971,7 +965,7 @@ int main(int argc, char** argv)
// Peers // Peers
mvwprintw(peerswin, 0, x, "Peers: "); mvwprintw(peerswin, 0, x, "Peers: ");
mvwprintw(peerswin, 0, 9, toString(c.peers().size()).c_str()); mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str());
// Mining flag // Mining flag
if (c.isMining()) if (c.isMining())

2
package.sh

@ -3,7 +3,7 @@
opwd="$PWD" opwd="$PWD"
br=$(git branch | grep '\*' | sed 's/^..//') br=$(git branch | grep '\*' | sed 's/^..//')
n=cpp-ethereum-src-$(date "+%Y%m%d%H%M%S" --date="1970-01-01 $(git log -1 --date=short --pretty=format:%ct) sec GMT")-$(grep "EthVersion = " libethential/Common.cpp | sed 's/^[^"]*"//' | sed 's/".*$//')-$(git rev-parse HEAD | cut -c1-6) n=cpp-ethereum-src-$(date "+%Y%m%d%H%M%S" --date="1970-01-01 $(git log -1 --date=short --pretty=format:%ct) sec GMT")-$(grep "Version = " libdevcore/Common.cpp | sed 's/^[^"]*"//' | sed 's/".*$//')-$(git rev-parse HEAD | cut -c1-6)
cd /tmp cd /tmp
git clone "$opwd" $n git clone "$opwd" $n

1
sc/cmdline.cpp

@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <map> #include <map>
#include <string>
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
int main(int argv, char** argc) { int main(int argv, char** argc) {

3
test/TestHelper.cpp

@ -42,11 +42,14 @@ void mine(Client& c, int numBlocks)
void connectClients(Client& c1, Client& c2) void connectClients(Client& c1, Client& c2)
{ {
// TODO: Move to WebThree. eth::Client no longer handles networking.
#if 0
short c1Port = 20000; short c1Port = 20000;
short c2Port = 21000; short c2Port = 21000;
c1.startNetwork(c1Port); c1.startNetwork(c1Port);
c2.startNetwork(c2Port); c2.startNetwork(c2Port);
c2.connect("127.0.0.1", c1Port); c2.connect("127.0.0.1", c1Port);
#endif
} }
} }

2
test/peer.cpp

@ -46,7 +46,7 @@ int peerTest(int argc, char** argv)
remoteHost = argv[i]; remoteHost = argv[i];
} }
Host ph("Test", listenPort); Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty()) if (!remoteHost.empty())
ph.connect(remoteHost, remotePort); ph.connect(remoteHost, remotePort);

36
test/vm.cpp

@ -219,13 +219,13 @@ public:
if (li) if (li)
store[curKey] = curVal; store[curKey] = curVal;
li = s.first; li = s.first;
curKey = toString(li); curKey = "0x"+toHex(toCompactBigEndian(li));
curVal = mArray(); curVal = mArray();
} }
else else
for (; li != s.first; ++li) for (; li != s.first; ++li)
curVal.push_back(0); curVal.push_back(0);
push(curVal, s.second); curVal.push_back("0x"+toHex(toCompactBigEndian(s.second)));
++li; ++li;
} }
if (li) if (li)
@ -474,8 +474,9 @@ void doTests(json_spirit::mValue& v, bool _fillin)
BOOST_AUTO_TEST_CASE(vm_tests) BOOST_AUTO_TEST_CASE(vm_tests)
{ {
/*
// Populate tests first: // Populate tests first:
// try try
{ {
cnote << "Populating VM tests..."; cnote << "Populating VM tests...";
json_spirit::mValue v; json_spirit::mValue v;
@ -485,7 +486,7 @@ BOOST_AUTO_TEST_CASE(vm_tests)
dev::test::doTests(v, true); dev::test::doTests(v, true);
writeFile("../../../tests/vmtests.json", asBytes(json_spirit::write_string(v, true))); writeFile("../../../tests/vmtests.json", asBytes(json_spirit::write_string(v, true)));
} }
/* catch (std::exception const& e) catch (std::exception const& e)
{ {
BOOST_ERROR("Failed VM Test with Exception: " << e.what()); BOOST_ERROR("Failed VM Test with Exception: " << e.what());
}*/ }*/
@ -504,3 +505,30 @@ BOOST_AUTO_TEST_CASE(vm_tests)
BOOST_ERROR("Failed VM Test with Exception: " << e.what()); BOOST_ERROR("Failed VM Test with Exception: " << e.what());
} }
} }
BOOST_AUTO_TEST_CASE(vmArithmeticTest)
{
/*
cnote << "Populating VM tests...";
json_spirit::mValue v;
string s = asString(contents("../../../cpp-ethereum/test/vmArithmeticTestFiller.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'vmtests.json' is empty.");
json_spirit::read_string(s, v);
dev::test::doTests(v, true);
writeFile("../../../tests/vmArithmeticTest.json", asBytes(json_spirit::write_string(v, true)));
*/
try
{
cnote << "Testing VM arithmetic commands...";
json_spirit::mValue v;
string s = asString(contents("../../../tests/vmArithmeticTest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'vmArithmeticTest.json' is empty. Have you cloned the 'tests' repo branch develop?");
json_spirit::read_string(s, v);
dev::test::doTests(v, false);
}
catch (std::exception const& e)
{
BOOST_ERROR("Failed VM arithmetic test with Exception: " << e.what());
}
}

2055
test/vmArithmeticTestFiller.json

File diff suppressed because it is too large

2
third/CMakeLists.txt

@ -52,7 +52,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

141
third/MainWin.cpp

@ -31,6 +31,7 @@
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
#include <libethcore/Dagger.h> #include <libethcore/Dagger.h>
#include <libdevcrypto/FileSystem.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#include <libevm/VM.h> #include <libevm/VM.h>
@ -38,49 +39,14 @@
#include <libethereum/ExtVM.h> #include <libethereum/ExtVM.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include <libwebthree/WebThree.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
using namespace dev;
// types using namespace dev::eth;
using dev::bytes; using namespace dev::p2p;
using dev::bytesConstRef;
using dev::h160;
using dev::h256;
using dev::u160;
using dev::u256;
using dev::Address;
using dev::eth::BlockInfo;
using dev::eth::Client;
using dev::eth::Instruction;
using dev::KeyPair;
using dev::eth::NodeMode;
using dev::eth::BlockChain;
using dev::p2p::PeerInfo;
using dev::RLP;
using dev::Secret;
using dev::eth::Transaction;
using dev::eth::Executive;
// functions
using dev::toHex;
using dev::fromHex;
using dev::left160;
using dev::right160;
using dev::simpleDebugOut;
using dev::toLog2;
using dev::toString;
using dev::operator<<;
using dev::eth::units;
using dev::eth::compileLLL;
using dev::eth::disassemble;
using dev::eth::formatBalance;
using dev::eth::sha3;
// vars
using dev::g_logPost;
using dev::g_logVerbosity;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr) static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
{ {
@ -133,12 +99,13 @@ Main::Main(QWidget *parent) :
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_client.reset(new Client("Third")); m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}));
m_web3->connect(Host::pocHost());
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_ethereum = new QEthereum(this, m_client.get(), owned()); m_ethereum = new QEthereum(this, ethereum(), owned());
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
@ -181,6 +148,11 @@ Main::~Main()
writeSettings(); writeSettings();
} }
eth::Client* Main::ethereum() const
{
return m_web3->ethereum();
}
void Main::onKeysChanged() void Main::onKeysChanged()
{ {
installBalancesWatch(); installBalancesWatch();
@ -188,14 +160,14 @@ void Main::onKeysChanged()
unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f) unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f)
{ {
auto ret = m_client->installWatch(_tf); auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f; m_handlers[ret] = _f;
return ret; return ret;
} }
unsigned Main::installWatch(dev::h256 _tf, std::function<void()> const& _f) unsigned Main::installWatch(dev::h256 _tf, std::function<void()> const& _f)
{ {
auto ret = m_client->installWatch(_tf); auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f; m_handlers[ret] = _f;
return ret; return ret;
} }
@ -209,14 +181,14 @@ void Main::installWatches()
void Main::installNameRegWatch() void Main::installNameRegWatch()
{ {
m_client->uninstallWatch(m_nameRegFilter); ethereum()->uninstallWatch(m_nameRegFilter);
m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)m_client->stateAt(c_config, 0)), [=](){ onNameRegChange(); }); m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
} }
void Main::installCurrenciesWatch() void Main::installCurrenciesWatch()
{ {
m_client->uninstallWatch(m_currenciesFilter); ethereum()->uninstallWatch(m_currenciesFilter);
m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)m_client->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); }); m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
} }
void Main::installBalancesWatch() void Main::installBalancesWatch()
@ -224,9 +196,9 @@ void Main::installBalancesWatch()
dev::eth::MessageFilter tf; dev::eth::MessageFilter tf;
vector<Address> altCoins; vector<Address> altCoins;
Address coinsAddr = right160(m_client->stateAt(c_config, 1)); Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
for (unsigned i = 0; i < m_client->stateAt(coinsAddr, 0); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
altCoins.push_back(right160(m_client->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
tf.altered(i.address()); tf.altered(i.address());
@ -234,7 +206,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address()); tf.altered(c, (u160)i.address());
} }
m_client->uninstallWatch(m_balancesFilter); ethereum()->uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
} }
@ -295,8 +267,8 @@ QString Main::pretty(dev::Address _a) const
{ {
h256 n; h256 n;
if (h160 nameReg = (u160)m_client->stateAt(c_config, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
n = m_client->stateAt(nameReg, (u160)(_a)); n = ethereum()->stateAt(nameReg, (u160)(_a));
return fromRaw(n); return fromRaw(n);
} }
@ -322,8 +294,8 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size()); memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size()) if (_a.size())
{ {
if (h160 nameReg = (u160)m_client->stateAt(c_config, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = m_client->stateAt(nameReg, n)) if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a); return right160(a);
} }
if (_a.size() == 40) if (_a.size() == 40)
@ -351,11 +323,11 @@ QString Main::lookup(QString const& _a) const
*/ */
h256 ret; h256 ret;
if (h160 dnsReg = (u160)m_client->stateAt(c_config, 4, 0)) if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
ret = m_client->stateAt(dnsReg, n); ret = ethereum()->stateAt(dnsReg, n);
/* if (!ret) /* if (!ret)
if (h160 nameReg = (u160)m_client->stateAt(c_config, 0, 0)) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0))
ret = m_client->stateAt(nameReg, n2); ret = ethereum()->stateAt(nameReg, n2);
*/ */
if (ret && !((u256)ret >> 32)) if (ret && !((u256)ret >> 32))
return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]); return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]);
@ -385,7 +357,7 @@ void Main::writeSettings()
s.setValue("address", b); s.setValue("address", b);
s.setValue("url", ui->urlEdit->text()); s.setValue("url", ui->urlEdit->text());
bytes d = m_client->savePeers(); bytes d = m_web3->savePeers();
if (d.size()) if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size()); m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers); s.setValue("peers", m_peers);
@ -416,7 +388,7 @@ void Main::readSettings(bool _skipGeometry)
m_myKeys.append(KeyPair(k)); m_myKeys.append(KeyPair(k));
} }
} }
m_client->setAddress(m_myKeys.back().address()); ethereum()->setAddress(m_myKeys.back().address());
m_peers = s.value("peers").toByteArray(); m_peers = s.value("peers").toByteArray();
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed(); on_urlEdit_returnPressed();
@ -466,8 +438,8 @@ void Main::on_urlEdit_returnPressed()
void Main::refreshMining() void Main::refreshMining()
{ {
dev::eth::MineProgress p = m_client->miningProgress(); dev::eth::MineProgress p = ethereum()->miningProgress();
ui->mineStatus->setText(m_client->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
} }
void Main::refreshBalances() void Main::refreshBalances()
@ -477,18 +449,18 @@ void Main::refreshBalances()
ui->ourAccounts->clear(); ui->ourAccounts->clear();
u256 totalBalance = 0; u256 totalBalance = 0;
map<Address, pair<QString, u256>> altCoins; map<Address, pair<QString, u256>> altCoins;
Address coinsAddr = right160(m_client->stateAt(c_config, 1)); Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
for (unsigned i = 0; i < m_client->stateAt(coinsAddr, 0); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
altCoins[right160(m_client->stateAt(coinsAddr, m_client->stateAt(coinsAddr, i + 1)))] = make_pair(fromRaw(m_client->stateAt(coinsAddr, i + 1)), 0); altCoins[right160(ethereum()->stateAt(coinsAddr, ethereum()->stateAt(coinsAddr, i + 1)))] = make_pair(fromRaw(ethereum()->stateAt(coinsAddr, i + 1)), 0);
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
u256 b = m_client->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.address());
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)m_client->countAt(i.address())), ui->ourAccounts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
totalBalance += b; totalBalance += b;
for (auto& c: altCoins) for (auto& c: altCoins)
c.second.second += (u256)m_client->stateAt(c.first, (u160)i.address()); c.second.second += (u256)ethereum()->stateAt(c.first, (u160)i.address());
} }
QString b; QString b;
@ -500,7 +472,7 @@ void Main::refreshBalances()
void Main::refreshNetwork() void Main::refreshNetwork()
{ {
auto ps = m_client->peers(); auto ps = m_web3->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
} }
@ -514,8 +486,8 @@ void Main::refreshAll()
void Main::refreshBlockCount() void Main::refreshBlockCount()
{ {
cwatch << "refreshBlockCount()"; cwatch << "refreshBlockCount()";
auto d = m_client->blockChain().details(); auto d = ethereum()->blockChain().details();
auto diff = BlockInfo(m_client->blockChain().block()).difficulty; auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("#%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion)); ui->blockCount->setText(QString("#%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion));
} }
@ -543,7 +515,7 @@ void Main::timerEvent(QTimerEvent*)
m_ethereum->poll(); m_ethereum->poll();
for (auto const& i: m_handlers) for (auto const& i: m_handlers)
if (m_client->checkWatch(i.first)) if (ethereum()->checkWatch(i.first))
i.second(); i.second();
} }
@ -574,7 +546,7 @@ void Main::ensureNetwork()
{ {
string n = string("Third/v") + dev::Version; string n = string("Third/v") + dev::Version;
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM); n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);
m_client->setClientVersion(n); web3()->setClientVersion(n);
int pocnumber = QString(dev::Version).section('.', 1, 1).toInt(); int pocnumber = QString(dev::Version).section('.', 1, 1).toInt();
string defPeer; string defPeer;
@ -583,13 +555,16 @@ void Main::ensureNetwork()
else if (pocnumber == 6) else if (pocnumber == 6)
defPeer = "54.76.56.74"; defPeer = "54.76.56.74";
if (!m_client->haveNetwork()) if (!web3()->haveNetwork())
m_client->startNetwork(30303, defPeer); {
web3()->startNetwork();
web3()->connect(defPeer);
}
else else
if (!m_client->peerCount()) if (!m_web3->peerCount())
m_client->connect(defPeer); m_web3->connect(defPeer);
if (m_peers.size()) if (m_peers.size())
m_client->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size())); m_web3->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
} }
void Main::on_connect_triggered() void Main::on_connect_triggered()
@ -600,7 +575,7 @@ void Main::on_connect_triggered()
{ {
string host = s.section(":", 0, 0).toStdString(); string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt(); unsigned short port = s.section(":", 1).toInt();
m_client->connect(host, port); web3()->connect(host, port);
} }
} }
@ -608,11 +583,11 @@ void Main::on_mine_triggered()
{ {
if (ui->mine->isChecked()) if (ui->mine->isChecked())
{ {
m_client->setAddress(m_myKeys.last().address()); ethereum()->setAddress(m_myKeys.last().address());
m_client->startMining(); ethereum()->startMining();
} }
else else
m_client->stopMining(); ethereum()->stopMining();
} }
// extra bits needed to link on VS // extra bits needed to link on VS

8
third/MainWin.h

@ -36,7 +36,8 @@ namespace Ui {
class Main; class Main;
} }
namespace dev { namespace eth { namespace dev { class WebThreeDirect;
namespace eth {
class Client; class Client;
class State; class State;
class MessageFilter; class MessageFilter;
@ -52,7 +53,8 @@ public:
explicit Main(QWidget *parent = 0); explicit Main(QWidget *parent = 0);
~Main(); ~Main();
dev::eth::Client* client() { return m_client.get(); } dev::WebThreeDirect* web3() const { return m_web3.get(); }
dev::eth::Client* ethereum() const;
QList<dev::KeyPair> const& owned() const { return m_myKeys; } QList<dev::KeyPair> const& owned() const { return m_myKeys; }
@ -111,7 +113,7 @@ private:
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::eth::Client> m_client; std::unique_ptr<dev::WebThreeDirect> m_web3;
QList<dev::KeyPair> m_myKeys; QList<dev::KeyPair> m_myKeys;

2
walleth/MainWin.cpp

@ -61,7 +61,7 @@ Main::Main(QWidget *parent) :
g_qmlMain = this; g_qmlMain = this;
m_client.reset(new Client("Walleth", Address(), dev::eth::getDataDir() + "/Walleth")); m_client.reset(new Client("Walleth", Address(), dev::getDataDir() + "/Walleth"));
g_qmlClient = m_client.get(); g_qmlClient = m_client.get();

20
windows/Alethzero.vcxproj

@ -209,6 +209,24 @@
</CustomBuild> </CustomBuild>
<ClInclude Include="..\alethzero\Grapher.h" /> <ClInclude Include="..\alethzero\Grapher.h" />
<ClInclude Include="..\alethzero\GraphParameters.h" /> <ClInclude Include="..\alethzero\GraphParameters.h" />
<CustomBuild Include="..\alethzero\DownloadView.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)moc_%(FileName).cpp</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)moc_%(FileName).cpp</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)moc_%(FileName).cpp</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)moc_%(FileName).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="..\alethzero\MiningView.h"> <CustomBuild Include="..\alethzero\MiningView.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -289,4 +307,4 @@
</ItemGroup> </ItemGroup>
<Copy SourceFiles="@(CopyToBinDir)" DestinationFiles="@(CopyToBinDir->'..\..\_binaries\$(Platform)\%(RecursiveDir)%(Filename)%(Extension)')" /> <Copy SourceFiles="@(CopyToBinDir)" DestinationFiles="@(CopyToBinDir->'..\..\_binaries\$(Platform)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target> </Target>
</Project> </Project>

2
windows/Ethereum.sln

@ -23,8 +23,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibMiniUPnPc", "LibMiniUPnP
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AlethZero", "Alethzero.vcxproj", "{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AlethZero", "Alethzero.vcxproj", "{BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Walleth", "Walleth.vcxproj", "{326EF470-463F-4751-A22A-48BBAAD8B143}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibQEthereum", "LibQEthereum.vcxproj", "{DF3C5B07-A1A2-4F16-B37F-A27333622CDD}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibQEthereum", "LibQEthereum.vcxproj", "{DF3C5B07-A1A2-4F16-B37F-A27333622CDD}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eth", "Eth.vcxproj", "{C60C065C-2135-4B2B-AFD4-35FD7AC56B40}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eth", "Eth.vcxproj", "{C60C065C-2135-4B2B-AFD4-35FD7AC56B40}"

2
windows/LibEthereum.vcxproj

@ -527,4 +527,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

6
windows/LibEthereum.vcxproj.filters

@ -175,6 +175,9 @@
<ClCompile Include="..\libwhisper\WhisperPeer.cpp"> <ClCompile Include="..\libwhisper\WhisperPeer.cpp">
<Filter>libwhisper</Filter> <Filter>libwhisper</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\libethereum\Manifest.cpp">
<Filter>libethereum</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
@ -384,6 +387,9 @@
<ClInclude Include="..\libwhisper\WhisperPeer.h"> <ClInclude Include="..\libwhisper\WhisperPeer.h">
<Filter>libwhisper</Filter> <Filter>libwhisper</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libethereum\Manifest.h">
<Filter>libethereum</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Windows"> <Filter Include="Windows">

Loading…
Cancel
Save