diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46cc0753f..6c6ec18cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -353,7 +353,7 @@ if (NOT LANGUAGES)
add_subdirectory(exp)
endif ()
if(NOT ("${TARGET_PLATFORM}" STREQUAL "w64"))
- add_subdirectory(neth)
+ #add_subdirectory(neth) // resurect once moved over to WebThree API.
endif ()
if(QTQML)
add_definitions(-DETH_QTQML)
@@ -369,7 +369,7 @@ if (NOT LANGUAGES)
add_subdirectory(third)
if(QTQML)
#add_subdirectory(iethxi)
- add_subdirectory(walleth)
+ #add_subdirectory(walleth) // resurect once we want to submit ourselves to QML.
endif()
endif()
endif()
diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt
index 3eac0a0b6..c5d1aa0be 100644
--- a/alethzero/CMakeLists.txt
+++ b/alethzero/CMakeLists.txt
@@ -52,7 +52,7 @@ else ()
endif ()
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)
# First have qt5 install plugins and frameworks
diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp
new file mode 100644
index 000000000..0fe5e1414
--- /dev/null
+++ b/alethzero/DownloadView.cpp
@@ -0,0 +1,40 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+/** @file DownloadView.cpp
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#include "DownloadView.h"
+
+#include
+#include
+#include
+#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);
+}
diff --git a/alethzero/DownloadView.h b/alethzero/DownloadView.h
new file mode 100644
index 000000000..ea3e05b8f
--- /dev/null
+++ b/alethzero/DownloadView.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+/** @file DownloadView.h
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#pragma once
+
+#ifdef Q_MOC_RUN
+#define BOOST_MPL_IF_HPP_INCLUDED
+#endif
+
+#include
+#include
+#ifndef Q_MOC_RUN
+#include
+#endif
+
+namespace dev { namespace eth {
+struct MineInfo;
+}}
+
+class DownloadView: public QWidget
+{
+ Q_OBJECT
+
+public:
+ DownloadView(QWidget* _p = nullptr);
+
+protected:
+ virtual void paintEvent(QPaintEvent*);
+
+private:
+};
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index aa8a43f1c..dbc4bb144 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -132,6 +132,7 @@
+
@@ -1432,6 +1433,39 @@ font-size: 14pt
+
+
+ QDockWidget::DockWidgetFeatureMask
+
+
+ Blockchain Download
+
+
+ 2
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
&Quit
@@ -1698,6 +1732,14 @@ font-size: 14pt
Reserved Debug 1
+
+
+ true
+
+
+ Enable Local Addresses
+
+
@@ -1712,6 +1754,12 @@ font-size: 14pt
1
+
+ DownloadView
+ QWidget
+
+ 1
+
destination
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index e9cdf90bc..5842664b3 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -43,45 +44,9 @@
#include "MainWin.h"
#include "ui_Main.h"
using namespace std;
-
-// types
-using dev::bytes;
-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;
+using namespace dev;
+using namespace dev::p2p;
+using namespace dev::eth;
static void initUnits(QComboBox* _b)
{
@@ -114,7 +79,6 @@ static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
return QString();
}
-
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Main::Main(QWidget *parent) :
@@ -177,12 +141,12 @@ Main::Main(QWidget *parent) :
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("AlethZero", getDataDir() + "/AlethZero", false, {"eth", "shh"}));
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// 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();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
@@ -226,6 +190,11 @@ Main::~Main()
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()
{
installBalancesWatch();
@@ -233,14 +202,14 @@ void Main::onKeysChanged()
unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function const& _f)
{
- auto ret = client()->installWatch(_tf);
+ auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f;
return ret;
}
unsigned Main::installWatch(dev::h256 _tf, std::function const& _f)
{
- auto ret = client()->installWatch(_tf);
+ auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f;
return ret;
}
@@ -255,14 +224,14 @@ void Main::installWatches()
void Main::installNameRegWatch()
{
- client()->uninstallWatch(m_nameRegFilter);
- m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)client()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
+ ethereum()->uninstallWatch(m_nameRegFilter);
+ m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
}
void Main::installCurrenciesWatch()
{
- client()->uninstallWatch(m_currenciesFilter);
- m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)client()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
+ ethereum()->uninstallWatch(m_currenciesFilter);
+ m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
}
void Main::installBalancesWatch()
@@ -270,9 +239,9 @@ void Main::installBalancesWatch()
dev::eth::MessageFilter tf;
vector altCoins;
- Address coinsAddr = right160(client()->stateAt(c_config, 1));
- for (unsigned i = 0; i < client()->stateAt(coinsAddr, 0); ++i)
- altCoins.push_back(right160(client()->stateAt(coinsAddr, i + 1)));
+ Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
+ for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
+ altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys)
{
tf.altered(i.address());
@@ -280,7 +249,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address());
}
- client()->uninstallWatch(m_balancesFilter);
+ ethereum()->uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
}
@@ -328,7 +297,7 @@ void Main::onNewPending()
void Main::on_forceMining_triggered()
{
- client()->setForceMining(ui->forceMining->isChecked());
+ ethereum()->setForceMining(ui->forceMining->isChecked());
}
void Main::on_enableOptimizer_triggered()
@@ -422,11 +391,11 @@ QString Main::pretty(dev::Address _a) const
{
h256 n;
- if (h160 nameReg = (u160)client()->stateAt(c_config, 0))
- n = client()->stateAt(nameReg, (u160)(_a));
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
+ n = ethereum()->stateAt(nameReg, (u160)(_a));
if (!n)
- n = client()->stateAt(m_nameReg, (u160)(_a));
+ n = ethereum()->stateAt(m_nameReg, (u160)(_a));
return fromRaw(n);
}
@@ -452,11 +421,11 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size())
{
- if (h160 nameReg = (u160)client()->stateAt(c_config, 0))
- if (h256 a = client()->stateAt(nameReg, n))
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
+ if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
- if (h256 a = client()->stateAt(m_nameReg, n))
+ if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}
if (_a.size() == 40)
@@ -484,11 +453,11 @@ QString Main::lookup(QString const& _a) const
*/
h256 ret;
- if (h160 dnsReg = (u160)client()->stateAt(c_config, 4, 0))
- ret = client()->stateAt(dnsReg, n);
+ if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
+ ret = ethereum()->stateAt(dnsReg, n);
/* if (!ret)
- if (h160 nameReg = (u160)m_client->stateAt(c_config, 0, 0))
- ret = m_client->stateAt(nameReg, n2);
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0))
+ ret = ethereum()->stateAt(nameReg, n2);
*/
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]);
@@ -506,7 +475,7 @@ void Main::on_about_triggered()
void Main::on_paranoia_triggered()
{
- client()->setParanoia(ui->paranoia->isChecked());
+ ethereum()->setParanoia(ui->paranoia->isChecked());
}
void Main::writeSettings()
@@ -525,6 +494,7 @@ void Main::writeSettings()
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked());
+ s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("showAll", ui->showAll->isChecked());
@@ -537,7 +507,7 @@ void Main::writeSettings()
s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value());
- bytes d = client()->savePeers();
+ bytes d = m_webThree->savePeers();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers);
@@ -569,11 +539,12 @@ void Main::readSettings(bool _skipGeometry)
m_myKeys.append(KeyPair(k));
}
}
- client()->setAddress(m_myKeys.back().address());
+ ethereum()->setAddress(m_myKeys.back().address());
m_peers = s.value("peers").toByteArray();
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
+ ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@@ -665,17 +636,17 @@ void Main::on_nameReg_textChanged()
void Main::on_preview_triggered()
{
- client()->setDefault(ui->preview->isChecked() ? 0 : -1);
+ ethereum()->setDefault(ui->preview->isChecked() ? 0 : -1);
refreshAll();
}
void Main::refreshMining()
{
- dev::eth::MineProgress p = client()->miningProgress();
- ui->mineStatus->setText(client()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
+ dev::eth::MineProgress p = ethereum()->miningProgress();
+ 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())
return;
- list l = client()->miningHistory();
+ list l = ethereum()->miningHistory();
static unsigned lh = 0;
if (p.hashes < lh)
ui->miningView->resetStats();
@@ -694,12 +665,12 @@ void Main::refreshBalances()
ui->ourAccounts->clear();
u256 totalBalance = 0;
map> altCoins;
- Address coinsAddr = right160(client()->stateAt(c_config, 1));
- for (unsigned i = 0; i < client()->stateAt(coinsAddr, 0); ++i)
+ Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
+ for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
{
- auto n = client()->stateAt(coinsAddr, i + 1);
- auto addr = right160(client()->stateAt(coinsAddr, n));
- auto denom = client()->stateAt(coinsAddr, sha3(h256(n).asBytes()));
+ auto n = ethereum()->stateAt(coinsAddr, i + 1);
+ auto addr = right160(ethereum()->stateAt(coinsAddr, n));
+ auto denom = ethereum()->stateAt(coinsAddr, sha3(h256(n).asBytes()));
if (denom == 0)
denom = 1;
// cdebug << n << addr << denom << sha3(h256(n).asBytes());
@@ -707,13 +678,13 @@ void Main::refreshBalances()
}
for (auto i: m_myKeys)
{
- u256 b = client()->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))
+ u256 b = ethereum()->balanceAt(i.address());
+ (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));
totalBalance += b;
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;
@@ -729,7 +700,7 @@ void Main::refreshBalances()
void Main::refreshNetwork()
{
- auto ps = client()->peers();
+ auto ps = web3()->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear();
@@ -751,7 +722,7 @@ void Main::refreshPending()
{
cwatch << "refreshPending()";
ui->transactionQueue->clear();
- for (Transaction const& t: client()->pending())
+ for (Transaction const& t: ethereum()->pending())
{
QString s = t.receiveAddress ?
QString("%2 %5> %3: %1 [%4]")
@@ -759,7 +730,7 @@ void Main::refreshPending()
.arg(render(t.safeSender()))
.arg(render(t.receiveAddress))
.arg((unsigned)t.nonce)
- .arg(client()->codeAt(t.receiveAddress).size() ? '*' : '-') :
+ .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString("%2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender()))
@@ -775,16 +746,16 @@ void Main::refreshAccounts()
ui->accounts->clear();
ui->contracts->clear();
for (auto n = 0; n < 2; ++n)
- for (auto i: client()->addresses())
+ for (auto i: ethereum()->addresses())
{
auto r = render(i);
if (r.contains('(') == !n)
{
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));
- if (client()->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))
+ if (ethereum()->codeAt(i).size())
+ (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));
}
}
@@ -794,7 +765,7 @@ void Main::refreshDestination()
{
cwatch << "refreshDestination()";
QString s;
- for (auto i: client()->addresses())
+ for (auto i: ethereum()->addresses())
if ((s = pretty(i)).size())
// A namereg address
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
@@ -807,8 +778,8 @@ void Main::refreshDestination()
void Main::refreshBlockCount()
{
cwatch << "refreshBlockCount()";
- auto d = client()->blockChain().details();
- auto diff = BlockInfo(client()->blockChain().block()).difficulty;
+ auto d = ethereum()->blockChain().details();
+ 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"));
}
@@ -839,7 +810,7 @@ static bool transactionMatch(string const& _f, Transaction const& _t)
void Main::on_turboMining_triggered()
{
- client()->setTurboMining(ui->turboMining->isChecked());
+ ethereum()->setTurboMining(ui->turboMining->isChecked());
}
void Main::refreshBlockChain()
@@ -850,7 +821,7 @@ void Main::refreshBlockChain()
ui->blocks->clear();
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;
for (auto h = bc.currentHash(); h != bc.genesisHash() && bc.details(h) && i; h = bc.details(h).parent, --i)
{
@@ -877,7 +848,7 @@ void Main::refreshBlockChain()
.arg(render(t.safeSender()))
.arg(render(t.receiveAddress))
.arg((unsigned)t.nonce)
- .arg(client()->codeAt(t.receiveAddress).size() ? '*' : '-') :
+ .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender()))
@@ -948,7 +919,7 @@ void Main::timerEvent(QTimerEvent*)
m_ethereum->poll();
for (auto const& i: m_handlers)
- if (client()->checkWatch(i.first))
+ if (ethereum()->checkWatch(i.first))
i.second();
}
@@ -1019,9 +990,9 @@ void Main::on_transactionQueue_currentItemChanged()
stringstream s;
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();
h256 th = sha3(rlpList(ss, tx.nonce));
s << "" << th << "
";
@@ -1049,7 +1020,7 @@ void Main::on_transactionQueue_currentItemChanged()
// s << "Pre: " << fs.rootHash() << "
";
// s << "Post: " << ts.rootHash() << "";
- s << renderDiff(client()->diff(i, 0));
+ s << renderDiff(ethereum()->diff(i, 0));
}
ui->pendingInfo->setHtml(QString::fromStdString(s.str()));
@@ -1076,7 +1047,7 @@ void Main::on_inject_triggered()
{
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
bytes b = fromHex(s.toStdString());
- client()->inject(&b);
+ ethereum()->inject(&b);
}
void Main::on_blocks_currentItemChanged()
@@ -1090,8 +1061,8 @@ void Main::on_blocks_currentItemChanged()
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
- auto details = client()->blockChain().details(h);
- auto blockData = client()->blockChain().block(h);
+ auto details = ethereum()->blockChain().details(h);
+ auto blockData = ethereum()->blockChain().block(h);
auto block = RLP(blockData);
BlockInfo info(blockData);
@@ -1115,7 +1086,7 @@ void Main::on_blocks_currentItemChanged()
s << "
Bloom: " << details.bloom << "";
s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "";
s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "";
- s << "
Pre: " << BlockInfo(client()->blockChain().block(info.parentHash)).stateRoot << "";
+ s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
for (auto const& i: block[1])
s << "
" << sha3(i[0].data()).abridged() << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]";
s << "
Post: " << info.stateRoot << "";
@@ -1151,7 +1122,7 @@ void Main::on_blocks_currentItemChanged()
if (tx.data.size())
s << dev::memDump(tx.data, 16, true);
}
- s << renderDiff(client()->diff(txi, h));
+ s << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true);
@@ -1173,7 +1144,7 @@ void Main::on_debugCurrent_triggered()
if (!item->data(Qt::UserRole + 1).isNull())
{
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(new Executive(m_executiveState));
Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi);
@@ -1199,7 +1170,7 @@ void Main::on_debugDumpState_triggered(int _add)
if (f.is_open())
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
- f << client()->state(txi + _add, h) << endl;
+ f << ethereum()->state(txi + _add, h) << endl;
}
}
}
@@ -1265,10 +1236,10 @@ void Main::on_contracts_currentItemChanged()
stringstream s;
try
{
- auto storage = client()->storageAt(address);
+ auto storage = ethereum()->storageAt(address);
for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << " " << showbase << hex << prettyU256(i.second).toStdString() << "
";
- s << "Body Code
" << disassemble(client()->codeAt(address));
+ s << "Body Code
" << disassemble(ethereum()->codeAt(address));
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
}
catch (dev::eth::InvalidTrie)
@@ -1281,7 +1252,7 @@ void Main::on_contracts_currentItemChanged()
void Main::on_idealPeers_valueChanged()
{
- client()->setIdealPeerCount(ui->idealPeers->value());
+ m_webThree->setIdealPeerCount(ui->idealPeers->value());
}
void Main::on_ourAccounts_doubleClicked()
@@ -1427,7 +1398,7 @@ void Main::on_data_textChanged()
s = s.mid(1);
}
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));
if (!ui->gas->isEnabled())
@@ -1450,9 +1421,9 @@ void Main::on_killBlockchain_triggered()
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
- m_client.reset();
- m_client.reset(new Client("AlethZero", Address(), string(), true));
- m_ethereum->setClient(client());
+ web3()->stopNetwork();
+ ethereum()->killChain();
+ m_ethereum->setClient(ethereum());
readSettings(true);
installWatches();
refreshAll();
@@ -1495,7 +1466,7 @@ void Main::updateFee()
bool ok = false;
for (auto i: m_myKeys)
- if (client()->balanceAt(i.address()) >= totalReq)
+ if (ethereum()->balanceAt(i.address()) >= totalReq)
{
ok = true;
break;
@@ -1514,15 +1485,20 @@ void Main::on_net_triggered()
if (ui->clientName->text().size())
n += "/" + ui->clientName->text().toStdString();
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);
- client()->setClientVersion(n);
+ web3()->setClientVersion(n);
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();
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
- client()->stopNetwork();
+ web3()->stopNetwork();
}
void Main::on_connect_triggered()
@@ -1538,7 +1514,7 @@ void Main::on_connect_triggered()
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
- client()->connect(host, port);
+ web3()->connect(host, port);
}
}
@@ -1552,25 +1528,25 @@ void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
- client()->setAddress(m_myKeys.last().address());
- client()->startMining();
+ ethereum()->setAddress(m_myKeys.last().address());
+ ethereum()->startMining();
}
else
- client()->stopMining();
+ ethereum()->stopMining();
}
void Main::on_send_clicked()
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
- if (client()->balanceAt(i.address(), 0) >= totalReq)
+ if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{
debugFinished();
Secret s = i.secret();
if (isCreation())
- client()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
+ ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
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;
}
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
@@ -1583,10 +1559,10 @@ void Main::on_debug_clicked()
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
- if (client()->balanceAt(i.address()) >= totalReq)
+ if (ethereum()->balanceAt(i.address()) >= totalReq)
{
Secret s = i.secret();
- m_executiveState = client()->postState();
+ m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr(new Executive(m_executiveState));
Transaction t;
t.nonce = m_executiveState.transactionsFrom(dev::toAddress(s));
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index a3bfa718d..ce1a9b670 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
namespace Ui {
class Main;
@@ -69,7 +70,9 @@ public:
explicit Main(QWidget *parent = 0);
~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 const& owned() const { return m_myKeys; }
@@ -146,6 +149,8 @@ signals:
void poll();
private:
+ dev::p2p::NetworkPreferences netPrefs() const;
+
QString pretty(dev::Address _a) const;
QString prettyU256(dev::u256 _n) const;
@@ -200,7 +205,7 @@ private:
std::unique_ptr ui;
- std::unique_ptr m_client;
+ std::unique_ptr m_webThree;
std::map> m_handlers;
unsigned m_nameRegFilter = (unsigned)-1;
diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
index 93946aa8f..eee1d258b 100644
--- a/eth/CMakeLists.txt
+++ b/eth/CMakeLists.txt
@@ -4,13 +4,13 @@ aux_source_directory(. SRC_LIST)
include_directories(..)
link_directories(../libethcore)
-link_directories(../libethereum)
+link_directories(../libwebthree)
set(EXECUTABLE eth)
add_executable(${EXECUTABLE} ${SRC_LIST})
-target_link_libraries(${EXECUTABLE} ethereum)
+target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
if(MINIUPNPC_LS)
diff --git a/eth/EthStubServer.cpp b/eth/EthStubServer.cpp
index c82d61103..e0baaa9c7 100644
--- a/eth/EthStubServer.cpp
+++ b/eth/EthStubServer.cpp
@@ -25,14 +25,15 @@
#include
#include
#include
+#include
#include "CommonJS.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
-EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, Client& _client):
+EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3):
AbstractEthStubServer(_conn),
- m_client(_client)
+ m_web3(_web3)
{
}
@@ -59,20 +60,25 @@ Json::Value EthStubServer::procedures()
return ret;
}
+dev::eth::Client& EthStubServer::ethereum() const
+{
+ return *m_web3.ethereum();
+}
+
std::string EthStubServer::coinbase()
{
- return toJS(m_client.address());
+ return toJS(ethereum().address());
}
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)
{
// TODO
-// if (m_client.changed())
+// if (ethereum().changed())
return _as;
/* 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)
{
- 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);
}
@@ -100,17 +106,17 @@ std::string EthStubServer::gasPrice()
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()
{
- return m_client.haveNetwork();
+ return m_web3.haveNetwork();
}
bool EthStubServer::isMining()
{
- return m_client.isMining();
+ return ethereum().isMining();
}
std::string EthStubServer::key()
@@ -130,12 +136,12 @@ Json::Value EthStubServer::keys()
int EthStubServer::peerCount()
{
- return m_client.peerCount();
+ return m_web3.peerCount();
}
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)
@@ -145,13 +151,13 @@ std::string EthStubServer::stateAt(const std::string& _a, const std::string& x,
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();
}
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)
@@ -172,7 +178,7 @@ Json::Value EthStubServer::block(const std::string& _hash)
Json::Value EthStubServer::blockJson(const std::string& _hash)
{
Json::Value res;
- auto const& bc = m_client.blockChain();
+ auto const& bc = ethereum().blockChain();
auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block();
diff --git a/eth/EthStubServer.h b/eth/EthStubServer.h
index 1034dbc5e..469abed07 100644
--- a/eth/EthStubServer.h
+++ b/eth/EthStubServer.h
@@ -29,12 +29,12 @@
#include "abstractethstubserver.h"
#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
{
public:
- EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::eth::Client& _client);
+ EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3);
virtual Json::Value procedures();
virtual std::string balanceAt(std::string const& _a);
@@ -58,7 +58,8 @@ public:
virtual Json::Value block(const std::string&);
void setKeys(std::vector _keys) { m_keys = _keys; }
private:
- dev::eth::Client& m_client;
+ dev::eth::Client& ethereum() const;
+ dev::WebThreeDirect& m_web3;
std::vector m_keys;
Json::Value jsontypeToValue(int);
Json::Value blockJson(const std::string&);
diff --git a/eth/main.cpp b/eth/main.cpp
index bd71f6677..3ea02f744 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#if ETH_READLINE
#include
#include
@@ -43,6 +44,7 @@
#include "BuildInfo.h"
using namespace std;
using namespace dev;
+using namespace dev::p2p;
using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
@@ -110,7 +112,8 @@ void help()
<< " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp Use upnp for NAT (default: on)." << endl
- << " -o,--mode Start a full node or a peer node (Default: full)." << endl
+ << " -L,--local-networking Use peers whose addresses are local." << endl
+ << " -o,--mode Start a full node or a peer node (Default: full)." << endl
<< " -p,--port Connect to remote port (default: 30303)." << endl
<< " -r,--remote Connect to remote host (default: none)." << endl
<< " -s,--secret Set the secret key for use with send command (default: auto)." << endl
@@ -186,6 +189,7 @@ int main(int argc, char** argv)
#endif
string publicIP;
bool upnp = true;
+ bool useLocal = false;
bool forceMining = false;
string clientName;
@@ -231,10 +235,12 @@ int main(int argc, char** argv)
upnp = false;
else
{
- cerr << "Invalid UPnP option: " << m << endl;
+ cerr << "Invalid -n/--upnp option: " << m << endl;
return -1;
}
}
+ else if (arg == "-L" || arg == "--local-networking")
+ useLocal = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@@ -254,7 +260,7 @@ int main(int argc, char** argv)
mining = i;
else
{
- cerr << "Unknown mining option: " << m << endl;
+ cerr << "Unknown -m/--mining option: " << m << endl;
return -1;
}
}
@@ -296,22 +302,25 @@ int main(int argc, char** argv)
if (!clientName.empty())
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();
+ 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{"eth", "shh"} : set{}, netPrefs);
+ web3.setIdealPeerCount(peers);
+ eth::Client& c = *web3.ethereum();
+
c.setForceMining(forceMining);
+ c.setAddress(coinbase);
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
- c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
+ web3.startNetwork();
+ web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC
auto_ptr jsonrpcServer;
if (jsonrpc > -1)
{
- jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c));
+ jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening();
}
@@ -349,20 +358,20 @@ int main(int argc, char** argv)
iss >> cmd;
if (cmd == "netstart")
{
- unsigned port;
- iss >> port;
- c.startNetwork((short)port);
+ iss >> netPrefs.listenPort;
+ web3.setNetworkPreferences(netPrefs);
+ web3.startNetwork();
}
else if (cmd == "connect")
{
string addr;
unsigned port;
iss >> addr >> port;
- c.connect(addr, (short)port);
+ web3.connect(addr, (short)port);
}
else if (cmd == "netstop")
{
- c.stopNetwork();
+ web3.stopNetwork();
}
else if (cmd == "minestart")
{
@@ -395,7 +404,7 @@ int main(int argc, char** argv)
{
if (jsonrpc < 0)
jsonrpc = 8080;
- jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c));
+ jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening();
}
@@ -422,7 +431,7 @@ int main(int argc, char** argv)
}
else if (cmd == "peers")
{
- for (auto it: c.peers())
+ for (auto it: web3.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast(it.lastPing).count() << "ms"
<< endl;
@@ -742,7 +751,7 @@ int main(int argc, char** argv)
c.startMining();
while (true)
{
- if (c.blockChain().details().number - n == mining)
+ if (c.isMining() && c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
diff --git a/exp/main.cpp b/exp/main.cpp
index c49b13e44..77d4aa00f 100644
--- a/exp/main.cpp
+++ b/exp/main.cpp
@@ -322,20 +322,21 @@ int main(int argc, char** argv)
remoteHost = argv[i];
}
- Host ph("Test", listenPort, "", false, true);
+ Host ph("Test", NetworkPreferences(listenPort, "", false, true));
ph.registerCapability(new WhisperHost());
auto wh = ph.cap();
+ ph.start();
+
if (!remoteHost.empty())
ph.connect(remoteHost, remotePort);
/// Only interested in the packet if the lowest bit is 1
auto w = wh->installWatch(MessageFilter(std::vector >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}})));
+
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);
for (auto i: wh->checkWatch(w))
cnote << "New message:" << (u256)h256(wh->message(i).payload);
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index 325ba274e..ad779e35d 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.6.8b";
+char const* Version = "0.6.8c";
}
diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp
new file mode 100644
index 000000000..fe0a4fe92
--- /dev/null
+++ b/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 .
+*/
+/** @file Worker.cpp
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#include "Worker.h"
+
+#include
+#include
+#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(1));
+ 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;
+}
+
diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h
new file mode 100644
index 000000000..8f0baaf60
--- /dev/null
+++ b/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 .
+*/
+/** @file Worker.h
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#pragma once
+
+#include
+#include
+#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 m_work; ///< The network thread.
+ bool m_stop = false;
+ std::string m_name;
+};
+
+}
diff --git a/libdevcrypto/FileSystem.cpp b/libdevcrypto/FileSystem.cpp
index 1fb38b57f..e161c3234 100644
--- a/libdevcrypto/FileSystem.cpp
+++ b/libdevcrypto/FileSystem.cpp
@@ -31,9 +31,8 @@
#include
using namespace std;
using namespace dev;
-using namespace dev::eth;
-std::string dev::eth::getDataDir()
+std::string dev::getDataDir()
{
#ifdef _WIN32
char path[1024] = "";
diff --git a/libdevcrypto/FileSystem.h b/libdevcrypto/FileSystem.h
index 9c597c421..605545b0d 100644
--- a/libdevcrypto/FileSystem.h
+++ b/libdevcrypto/FileSystem.h
@@ -27,11 +27,8 @@
namespace dev
{
-namespace eth
-{
/// @returns the path for user data.
std::string getDataDir();
}
-}
diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h
index 8186acaee..283f11b88 100644
--- a/libethcore/BlockInfo.h
+++ b/libethcore/BlockInfo.h
@@ -56,7 +56,7 @@ extern u256 c_genesisDifficulty;
struct BlockInfo
{
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 sha3Uncles;
Address coinbaseAddress;
diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp
index f96fb5480..eed8b4bb9 100644
--- a/libethcore/CommonEth.cpp
+++ b/libethcore/CommonEth.cpp
@@ -34,7 +34,7 @@ namespace dev
namespace eth
{
-const unsigned c_protocolVersion = 32;
+const unsigned c_protocolVersion = 33;
const unsigned c_databaseVersion = 1;
static const vector> g_units =
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 716add2ae..181f4fd64 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -108,6 +108,20 @@ bytes BlockChain::createGenesisBlock()
}
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())
_path = Defaults::get()->m_dbPath;
@@ -127,10 +141,6 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!m_extrasDB)
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))
{
// Insert details of genesis block.
@@ -150,11 +160,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
cnote << "Opened blockchain DB. Latest: " << currentHash();
}
-BlockChain::~BlockChain()
+void BlockChain::close()
{
cnote << "Closing blockchain DB";
delete m_extrasDB;
delete m_db;
+ m_lastBlockHash = m_genesisHash;
+ m_details.clear();
+ m_blooms.clear();
+ m_traces.clear();
+ m_cache.clear();
}
template
@@ -245,21 +260,23 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first!
- if (details(newHash))
+ if (isKnown(newHash))
{
clog(BlockChainNote) << newHash << ": Not new.";
throw AlreadyHaveBlock();
}
// Work out its number as the parent's number + 1
- auto pd = details(bi.parentHash);
- if (!pd)
+ if (!isKnown(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.
throw UnknownParent();
}
+ auto pd = details(bi.parentHash);
+ assert(pd);
+
// Check it's not crazy
if (bi.timestamp > (u256)time(0))
{
@@ -432,6 +449,20 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
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
{
if (_hash == m_genesisHash)
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
index c0b3988a9..cf33a5104 100644
--- a/libethereum/BlockChain.h
+++ b/libethereum/BlockChain.h
@@ -70,6 +70,8 @@ public:
BlockChain(std::string _path, bool _killExisting = false);
~BlockChain();
+ void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); }
+
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so.
void process();
@@ -85,6 +87,9 @@ public:
/// @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);
+ /// 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.
BlockDetails details(h256 _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); }
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;
private:
+ void open(std::string _path, bool _killExisting = false);
+ void close();
+
template T queryExtras(h256 _h, std::map& _m, boost::shared_mutex& _x, T const& _n) const
{
{
diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp
index 21aeb5a72..a845965d5 100644
--- a/libethereum/BlockQueue.cpp
+++ b/libethereum/BlockQueue.cpp
@@ -74,21 +74,24 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
// Check it's not in the future
if (bi.timestamp > (u256)time(0))
+ {
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
+ cblockq << "OK - queued for future.";
+ }
else
{
// 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.
-// 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_unknownSet.insert(h);
}
else
{
// If valid, append to blocks.
-// cnote << "OK - ready for chain insertion.";
+ cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes());
m_readySet.insert(h);
diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h
index 5a4a86ad6..20bc4ce59 100644
--- a/libethereum/BlockQueue.h
+++ b/libethereum/BlockQueue.h
@@ -34,7 +34,7 @@ namespace eth
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()
/**
@@ -64,6 +64,9 @@ public:
/// Get information on the items queued.
std::pair 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:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 3bc159f17..d64c9fafb 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -53,94 +53,102 @@ 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):
+ Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(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())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
- work();
+ doWork();
+
+ startWorking();
}
Client::~Client()
{
- 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();
- m_work.reset(nullptr);
- }
- stopNetwork();
+ stopWorking();
}
-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)
- 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)
- work();
- m_workState.store(Deleted, std::memory_order_release);
-
- // Synchronise the state according to the head of the block chain.
- // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
- WriteGuard l(x_stateDB);
- m_preMine.sync(m_bc);
- m_postMine = m_preMine;
- }));
+void Client::doneWorking()
+{
+ // Synchronise the state according to the head of the block chain.
+ // 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()
{
- 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();
+
+ startWorking();
+ if (wasMining)
+ startMining();
}
void Client::clearPending()
{
- WriteGuard l(x_stateDB);
- if (!m_postMine.pending().size())
- return;
h256Set changeds;
- for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
- appendFromNewPending(m_postMine.bloom(i), changeds);
- changeds.insert(PendingChangedFilter);
- m_postMine = m_preMine;
+ {
+ WriteGuard l(x_stateDB);
+ if (!m_postMine.pending().size())
+ 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);
for (auto& m: m_miners)
m.noteStateChange();
}
+
noteChanged(changeds);
}
@@ -211,111 +219,10 @@ void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
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 Client::peers()
-{
- ReadGuard l(x_net);
- return m_net ? m_net->peers() : std::vector();
-}
-
-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)
{
m_forceMining = _enable;
- if (!m_extHost.lock())
+ if (!m_host.lock())
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
@@ -323,19 +230,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)
{
- if (m_extHost.lock())
- return;
-
stopMining();
auto t = _threads ? _threads : thread::hardware_concurrency();
@@ -350,8 +246,6 @@ void Client::setMiningThreads(unsigned _threads)
MineProgress Client::miningProgress() const
{
MineProgress ret;
- if (m_extHost.lock())
- return ret;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ret.combine(m.miningProgress());
@@ -361,8 +255,6 @@ MineProgress Client::miningProgress() const
std::list Client::miningHistory()
{
std::list ret;
- if (m_extHost.lock())
- return ret;
ReadGuard l(x_miners);
if (m_miners.empty())
@@ -404,7 +296,7 @@ void Client::setupState(State& _s)
void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
- ensureWorking();
+ startWorking();
Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
@@ -446,7 +338,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)
{
- ensureWorking();
+ startWorking();
Transaction t;
{
@@ -466,47 +358,18 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
void Client::inject(bytesConstRef _rlp)
{
- ensureWorking();
+ startWorking();
m_tq.attemptImport(_rlp);
}
-void Client::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_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())
- {
- cwork << "NET <==> TQ ; CHAIN ==> NET ==> BQ";
- m_net->cap()->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()
+void Client::doWork()
{
// TODO: Use condition variable rather than polling.
cworkin << "WORK";
h256Set changeds;
- if (!m_extHost.lock())
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
@@ -557,7 +420,8 @@ void Client::work()
cwork << "preSTATE <== CHAIN";
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;
rsm = true;
changeds.insert(PendingChangedFilter);
@@ -573,11 +437,12 @@ void Client::work()
appendFromNewPending(i, changeds);
changeds.insert(PendingChangedFilter);
- cnote << "Additional transaction ready: Restarting mining operation.";
+ if (isMining())
+ cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true;
}
}
- if (!m_extHost.lock() && rsm)
+ if (rsm)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
diff --git a/libethereum/Client.h b/libethereum/Client.h
index 8bdb48051..6415defb0 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -108,14 +109,11 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
/**
* @brief Main API hub for interfacing with Ethereum.
*/
-class Client: public MinerHost, public Interface
+class Client: public MinerHost, public Interface, Worker
{
friend class Miner;
public:
- /// Original Constructor.
- explicit Client(std::string const& _clientVersion, Address _us = Address(), std::string const& _dbPath = std::string(), bool _forceClean = false);
-
/// New-style Constructor.
explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0);
@@ -165,6 +163,9 @@ public:
// [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.
/// @TODO: Remove in favour of transactions().
Transactions pending() const { return m_postMine.pending(); }
@@ -192,32 +193,6 @@ public:
/// Get the object representing the current canonical blockchain.
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 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:
/// Check block validity prior to mining.
@@ -243,7 +218,7 @@ public:
unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
/// Start mining.
/// 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.
/// NOT thread-safe
void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
@@ -254,19 +229,20 @@ public:
/// Get and clear the mining history.
std::list miningHistory();
+ // Debug stuff:
+
+ /// Sets the network id.
+ void setNetworkId(u256 _n);
/// Clears pending transactions. Just for debug use.
void clearPending();
+ /// Kills the blockchain. Just for debug use.
+ void killChain();
private:
- /// Ensure the worker thread is running. Needed for blockchain maintenance & mining.
- void ensureWorking();
-
/// Do some work. Handles blockchain maintenance and mining.
- /// @param _justQueue If true will only processing the transaction queues.
- void work();
+ virtual void doWork();
- /// Do some work on the network.
- void workNet();
+ virtual void doneWorking();
/// Overrides for being a mining host.
virtual void setupState(State& _s);
@@ -291,26 +267,17 @@ private:
State asOf(int _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.
BlockChain m_bc; ///< Maintains block database.
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).
- // 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.
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_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
- std::unique_ptr m_workNet; ///< The network thread.
- std::atomic m_workNetState;
- mutable boost::shared_mutex x_net; ///< Lock for the network existance.
- std::unique_ptr m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
-
- std::weak_ptr m_extHost; ///< Our Ethereum Host. Don't do anything if we can't lock.
-
- std::unique_ptr m_work; ///< The work thread.
- std::atomic m_workState;
+ std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector m_miners;
mutable boost::shared_mutex x_miners;
diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h
index 3bb45b55d..6774c02ae 100644
--- a/libethereum/CommonNet.h
+++ b/libethereum/CommonNet.h
@@ -33,11 +33,17 @@ namespace dev
namespace eth
{
+#if ETH_DEBUG
+static const unsigned c_maxHashes = 4; ///< Maximum number of hashes BlockHashes will ever send.
+static const unsigned c_maxHashesAsk = 4; ///< Maximum number of hashes GetBlockHashes will ever ask for.
+static const unsigned c_maxBlocks = 2; ///< Maximum number of blocks Blocks will ever send.
+static const unsigned c_maxBlocksAsk = 2; ///< 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_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_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
-
+#endif
class OverlayDB;
class BlockChain;
class TransactionQueue;
@@ -55,5 +61,13 @@ enum EthereumPacket
BlocksPacket,
};
+enum class Grabbing
+{
+ State,
+ Hashes,
+ Chain,
+ Nothing
+};
+
}
}
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index 1e623b605..2add39482 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -39,11 +39,15 @@ using namespace dev;
using namespace dev::eth;
using namespace p2p;
-EthereumHost::EthereumHost(BlockChain const& _ch, u256 _networkId):
+EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability(),
- m_chain (&_ch),
+ Worker ("ethsync"),
+ m_chain (_ch),
+ m_tq (_tq),
+ m_bq (_bq),
m_networkId (_networkId)
{
+ m_latestBlockSent = _ch.currentHash();
}
EthereumHost::~EthereumHost()
@@ -68,20 +72,20 @@ h256Set EthereumHost::neededBlocks(h256Set const& _exclude)
m_blocksNeeded.erase(it);
}
}
- if (!ret.size())
+ if (ret.empty())
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.";
+ if (ret.size())
+ clog(NetMessageSummary) << "Asking for" << ret.size() << "blocks that we don't yet have." << m_blocksNeeded.size() << "blocks still needed," << m_blocksOnWay.size() << "total blocks on way.";
return ret;
}
bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
{
- if (m_latestBlockSent == h256())
+ if (!m_latestBlockSent)
{
// First time - just initialise.
- m_latestBlockSent = m_chain->currentHash();
+ m_latestBlockSent = m_chain.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();
for (auto const& i: _tq.transactions())
@@ -91,9 +95,85 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
return false;
}
+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->restartGettingChain();
+ 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()->restartGettingChain();
+}
+
+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 << "," << m_totalDifficultyOfNeeded << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
+
+ if ((m_totalDifficultyOfNeeded && (td < m_totalDifficultyOfNeeded || (td == m_totalDifficultyOfNeeded && m_latestBlockSent == _from->m_latestHash))) || 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.
+ {
+ Guard l(x_blocksNeeded);
+ m_blocksNeeded = _from->m_neededBlocks;
+ m_blocksOnWay.clear();
+ m_totalDifficultyOfNeeded = td;
+ 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()->tryGrabbingHashChain();
+ if (j->cap()->m_grabbing == Grabbing::Hashes)
+ {
+ m_grabbing = Grabbing::Hashes;
+ return;
+ }
+ }
+ clog(NetNote) << "No more peers to sync with.";
+}
+
void EthereumHost::noteDoneBlocks()
{
- clog(NetNote) << "Peer given up on blocks fetch.";
if (m_blocksOnWay.empty())
{
// Done our chain-get.
@@ -101,7 +181,7 @@ void EthereumHost::noteDoneBlocks()
clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks.";
else
clog(NetNote) << "No more blocks to get.";
- m_latestBlockSent = m_chain->currentHash();
+ updateGrabbing(Grabbing::Nothing);
}
}
@@ -109,7 +189,7 @@ bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
{
Guard l(x_blocksNeeded);
m_blocksOnWay.erase(_hash);
- if (!m_chain->details(_hash))
+ if (!m_chain.details(_hash))
{
lock_guard l(m_incomingLock);
m_incomingBlocks.push_back(_data.toBytes());
@@ -118,19 +198,20 @@ bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
return false;
}
-bool EthereumHost::sync(TransactionQueue& _tq, BlockQueue& _bq)
+void EthereumHost::doWork()
{
- bool netChange = ensureInitialised(_tq);
- auto h = m_chain->currentHash();
- maintainTransactions(_tq, h);
- maintainBlocks(_bq, h);
- return netChange;
+ bool netChange = ensureInitialised(m_tq);
+ auto h = m_chain.currentHash();
+ maintainTransactions(m_tq, h);
+ maintainBlocks(m_bq, h);
+// return netChange;
+ // TODO: Figure out what to do with netChange.
+ (void)netChange;
}
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash)
{
bool resendAll = (_currentHash != m_latestBlockSent);
-
{
lock_guard l(m_incomingLock);
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
@@ -172,34 +253,43 @@ void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash
}
}
+void EthereumHost::reset()
+{
+ m_grabbing = Grabbing::Nothing;
+
+ m_incomingTransactions.clear();
+ m_incomingBlocks.clear();
+
+ m_totalDifficultyOfNeeded = 0;
+ m_blocksNeeded.clear();
+ m_blocksOnWay.clear();
+
+ m_latestBlockSent = h256();
+ m_transactionsSent.clear();
+}
+
void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
{
// Import new blocks
{
lock_guard l(m_incomingLock);
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.
m_incomingBlocks.clear();
}
- // If we've finished our initial sync...
- {
- Guard l(x_blocksNeeded);
- if (m_blocksOnWay.size())
- return;
- }
- // ...send any new blocks.
- if (m_latestBlockSent != _currentHash)
+ // If we've finished our initial sync send any new blocks.
+ if (m_grabbing == Grabbing::Nothing && m_chain.details(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
RLPStream ts;
EthereumPeer::prep(ts);
bytes bs;
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;
}
clog(NetMessageSummary) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
@@ -211,6 +301,7 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
for (auto j: peers())
{
auto p = j->cap();
+ Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
p->send(&b);
p->m_knownBlocks.clear();
@@ -218,32 +309,3 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _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()->restartGettingChain();
-}
diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h
index 6cd9332a2..c875d74fe 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include "CommonNet.h"
@@ -45,28 +46,149 @@ namespace eth
class TransactionQueue;
class BlockQueue;
+using UnsignedRange = std::pair;
+using UnsignedRanges = std::vector;
+
+class RangeMask
+{
+public:
+ RangeMask() {}
+ RangeMask(unsigned _begin, unsigned _end): m_ranges({{_begin, _end}}) {}
+
+ 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 must contain the value.
+ auto it = m_ranges.lower_bound(i);
+ auto uit = m_ranges.upper_bound(i + 1);
+ 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+=(unsigned _i)
+ {
+ return operator+=(UnsignedRange(_i, _i + 1));
+ }
+
+ bool contains(unsigned _i) const
+ {
+ auto it = m_ranges.lower_bound(_i);
+ return it != m_ranges.end() && it->first <= _i && it->second > _i;
+ }
+
+private:
+ std::map m_ranges;
+};
+
+#if 0
+class DownloadSub
+{
+ friend class DownloadMan;
+
+public:
+ h256s nextFetch();
+ void noteBlock(h256 _hash, bytesConstRef _data);
+
+private:
+ void resetFetch(); // Called by DownloadMan when we need to reset the download.
+
+ DownloadMan* m_man;
+
+ Mutex m_fetch;
+ h256s m_fetching;
+ h256s m_activeGet;
+ bool m_killFetch;
+ RangeMask m_attempted;
+};
+
+class DownloadMan
+{
+ friend class DownloadSub;
+
+public:
+ void resetToChain(h256s const& _chain);
+
+private:
+ void cancelFetch(DownloadSub* );
+ void noteBlock(h256 _hash, bytesConstRef _data);
+
+ h256s m_chain;
+ RangeMask m_complete;
+ std::map m_fetching;
+};
+#endif
+
/**
* @brief The EthereumHost class
* @warning None of this is thread-safe. You have been warned.
*/
-class EthereumHost: public p2p::HostCapability
+class EthereumHost: public p2p::HostCapability, Worker
{
friend class EthereumPeer;
public:
/// 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.
virtual ~EthereumHost();
unsigned protocolVersion() const { return c_protocolVersion; }
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.
- bool sync(TransactionQueue&, BlockQueue& _bc);
+ void reset();
private:
+ void noteHavePeerState(EthereumPeer* _who);
/// Session wants to pass us a block that we might not have.
/// @returns true if we didn't have it.
bool noteBlock(h256 _hash, bytesConstRef _data);
@@ -75,9 +197,12 @@ private:
/// Called when the peer can no longer provide us with any needed blocks.
void noteDoneBlocks();
+ /// 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 l(m_incomingLock); m_incomingTransactions.push_back(_bytes); }
-
+
void maintainTransactions(TransactionQueue& _tq, h256 _currentBlock);
void maintainBlocks(BlockQueue& _bq, h256 _currentBlock);
@@ -87,15 +212,25 @@ private:
h256Set neededBlocks(h256Set const& _exclude);
/// 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.
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;
+ Grabbing m_grabbing = Grabbing::Nothing;
+
mutable std::recursive_mutex m_incomingLock;
std::vector m_incomingTransactions;
std::vector m_incomingBlocks;
@@ -106,7 +241,7 @@ private:
h256Set m_blocksOnWay;
h256 m_latestBlockSent;
- std::set m_transactionsSent;
+ h256Set m_transactionsSent;
};
}
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index c961f6733..7ccf6939b 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -57,9 +57,9 @@ void EthereumPeer::sendStatus()
s.appendList(6) << StatusPacket
<< host()->protocolVersion()
<< host()->networkId()
- << host()->m_chain->details().totalDifficulty
- << host()->m_chain->currentHash()
- << host()->m_chain->genesisHash();
+ << host()->m_chain.details().totalDifficulty
+ << host()->m_chain.currentHash()
+ << host()->m_chain.genesisHash();
sealAndSend(s);
}
@@ -73,16 +73,35 @@ void EthereumPeer::startInitialSync()
sealAndSend(s);
}
- h256 c = host()->m_chain->currentHash();
- unsigned n = host()->m_chain->number();
- u256 td = max(host()->m_chain->details().totalDifficulty, host()->m_totalDifficultyOfNeeded);
+ host()->noteHavePeerState(this);
+}
+
+void EthereumPeer::tryGrabbingHashChain()
+{
+ // if already done this, then ignore.
+ if (m_grabbing != Grabbing::State)
+ {
+ clogS(NetAllDetail) << "Already synced with this peer.";
+ return;
+ }
- clogS(NetAllDetail) << "Initial sync. Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << host()->m_chain->details().totalDifficulty << "," << host()->m_totalDifficultyOfNeeded << ") versus " << m_totalDifficulty;
+ h256 c = host()->m_chain.currentHash();
+ unsigned n = host()->m_chain.number();
+ u256 td = max(host()->m_chain.details().totalDifficulty, host()->m_totalDifficultyOfNeeded);
+
+ clogS(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << host()->m_chain.details().totalDifficulty << "," << host()->m_totalDifficultyOfNeeded << ") 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.
+ }
// Our chain isn't better - grab theirs.
{
+ clogS(NetAllDetail) << "Yes. Their chain is better.";
+
+ m_grabbing = Grabbing::Hashes;
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
@@ -94,6 +113,16 @@ void EthereumPeer::startInitialSync()
void EthereumPeer::giveUpOnFetch()
{
clogS(NetNote) << "GIVE UP FETCH; can't get" << toString(m_askedBlocks);
+
+ // 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::Nothing;
+ host()->updateGrabbing(Grabbing::Nothing);
+ }
+
+ // NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
+
if (m_askedBlocks.size())
{
Guard l (host()->x_blocksNeeded);
@@ -122,7 +151,7 @@ bool EthereumPeer::interpret(RLP const& _r)
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");
if (m_protocolVersion != host()->protocolVersion())
disable("Invalid protocol version.");
@@ -138,8 +167,10 @@ bool EthereumPeer::interpret(RLP const& _r)
break;
}
case TransactionsPacket:
+ {
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)";
addRating(_r.itemCount() - 1);
+ lock_guard l(host()->m_incomingLock);
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
host()->addIncomingTransaction(_r[i].data().toBytes());
@@ -148,25 +179,32 @@ bool EthereumPeer::interpret(RLP const& _r)
m_knownTransactions.insert(sha3(_r[i].data()));
}
break;
+ }
case GetBlockHashesPacket:
{
h256 later = _r[1].toHash();
unsigned limit = _r[2].toInt();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")";
- unsigned c = min(host()->m_chain->number(later), limit);
+ unsigned c = min(max(1, host()->m_chain.number(later)) - 1, limit);
RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket);
- h256 p = host()->m_chain->details(later).parent;
- for (unsigned i = 0; i < c; ++i, p = host()->m_chain->details(p).parent)
+ h256 p = host()->m_chain.details(later).parent;
+ for (unsigned i = 0; i < c; ++i, p = host()->m_chain.details(p).parent)
s << p;
sealAndSend(s);
break;
}
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)
{
host()->noteHaveChain(this);
@@ -175,7 +213,7 @@ bool EthereumPeer::interpret(RLP const& _r)
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = _r[i].toHash();
- if (host()->m_chain->details(h))
+ if (host()->m_chain.details(h))
{
host()->noteHaveChain(this);
return true;
@@ -193,12 +231,12 @@ bool EthereumPeer::interpret(RLP const& _r)
case GetBlocksPacket:
{
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)";
- // TODO: return the requested blocks.
+ // return the requested blocks.
bytes rlp;
unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
{
- auto b = host()->m_chain->block(_r[i].toHash());
+ auto b = host()->m_chain.block(_r[i].toHash());
if (b.size())
{
rlp += b;
@@ -211,7 +249,7 @@ bool EthereumPeer::interpret(RLP const& _r)
}
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)
{
@@ -227,6 +265,7 @@ bool EthereumPeer::interpret(RLP const& _r)
if (host()->noteBlock(h, _r[i].data()))
used++;
m_askedBlocks.erase(h);
+ Guard l(x_knownBlocks);
m_knownBlocks.insert(h);
}
addRating(used);
@@ -238,7 +277,8 @@ bool EthereumPeer::interpret(RLP const& _r)
{
auto h = BlockInfo::headerHash(_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++;
clogS(NetAllDetail) << "Unknown parent" << bi.parentHash << "of block" << h;
@@ -296,7 +336,8 @@ void EthereumPeer::continueGettingChain()
}
else
{
- clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have" << m_failedBlocks.size() << "of our needed blocks.";
+ if (m_failedBlocks.size())
+ clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have" << m_failedBlocks.size() << "of our needed blocks.";
host()->noteDoneBlocks();
}
}
diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h
index 92eb475ec..7248fabd0 100644
--- a/libethereum/EthereumPeer.h
+++ b/libethereum/EthereumPeer.h
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include
#include "CommonNet.h"
@@ -58,6 +59,8 @@ private:
void sendStatus();
void startInitialSync();
+ void tryGrabbingHashChain();
+
/// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
@@ -72,6 +75,8 @@ private:
unsigned m_protocolVersion;
u256 m_networkId;
+ Grabbing m_grabbing = Grabbing::State;
+
h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer.
@@ -82,6 +87,7 @@ private:
bool m_requireTransactions;
+ Mutex x_knownBlocks;
std::set m_knownBlocks;
std::set m_knownTransactions;
std::mutex x_knownTransactions;
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index e8c1fd1cb..a6b57a05c 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -187,6 +187,7 @@ bool Executive::go(OnOpFunc const& _onOp)
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
+ m_endGas = m_vm->gas();
}
catch (Exception const& _e)
{
diff --git a/libethereum/Interface.h b/libethereum/Interface.h
index 3fa93a286..a5df3e5b1 100644
--- a/libethereum/Interface.h
+++ b/libethereum/Interface.h
@@ -95,8 +95,13 @@ public:
virtual bool peekWatch(unsigned _watchId) const = 0;
virtual bool checkWatch(unsigned _watchId) = 0;
+ // TODO: Block query API.
+
// [EXTRA API]:
+ /// @returns The height of the chain.
+ virtual unsigned number() const = 0;
+
/// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions().
virtual Transactions pending() const = 0;
diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp
index c602cedc1..9b651e2c5 100644
--- a/libethereum/Miner.cpp
+++ b/libethereum/Miner.cpp
@@ -27,42 +27,12 @@ using namespace dev;
using namespace dev::eth;
Miner::Miner(MinerHost* _host, unsigned _id):
- m_host(_host),
- m_id(_id)
+ Worker("miner-" + toString(_id)),
+ m_host(_host)
{
}
-void Miner::start()
-{
- 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()
+void Miner::doWork()
{
// Do some mining.
if (m_miningStatus != Waiting && m_miningStatus != Mined)
diff --git a/libethereum/Miner.h b/libethereum/Miner.h
index 8912b0e2a..763249b7d 100644
--- a/libethereum/Miner.h
+++ b/libethereum/Miner.h
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include "State.h"
@@ -74,38 +75,38 @@ public:
* @threadsafe
* @todo Signal Miner to restart once with condition variables.
*/
-class Miner
+class Miner: Worker
{
public:
/// Null constructor.
- Miner(): m_host(nullptr), m_id(0) {}
+ Miner(): m_host(nullptr) {}
/// Constructor.
Miner(MinerHost* _host, unsigned _id = 0);
/// 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.
- 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.
~Miner() { stop(); }
/// 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.
- void start();
+ void start() { startWorking(); }
/// Stop mining.
- void stop();
+ void stop() { stopWorking(); }
/// Call to notify Miner of a state change.
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().
- bool isRunning() { return !!m_work; }
+ bool isRunning() { return isWorking(); }
/// @returns true if mining is complete.
bool isComplete() const { return m_miningStatus == Mined; }
@@ -121,14 +122,9 @@ public:
private:
/// Do some work on the mining.
- void work();
+ virtual void doWork();
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 m_work; ///< The work thread.
- bool m_stop = false; ///< Stop working?
enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped };
MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable.
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 093db299f..a74b6ba18 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -152,10 +152,15 @@ State& State::operator=(State const& _s)
m_currentBlock = _s.m_currentBlock;
m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward;
+ m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true);
return *this;
}
+State::~State()
+{
+}
+
struct CachedAddressState
{
CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {}
diff --git a/libethereum/State.h b/libethereum/State.h
index 335f27168..fea8e06c7 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -90,6 +90,8 @@ public:
/// Copy state object.
State& operator=(State const& _s);
+ ~State();
+
/// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }
diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h
index 154eed9d2..22a420602 100644
--- a/libethereum/TransactionQueue.h
+++ b/libethereum/TransactionQueue.h
@@ -52,6 +52,8 @@ public:
void setFuture(std::pair const& _t);
void noteGood(std::pair const& _t);
+ void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
+
private:
mutable boost::shared_mutex m_lock; ///< General lock.
std::set m_known; ///< Hashes of transactions in both sets.
diff --git a/libevm/VM.h b/libevm/VM.h
index a07e225e6..cbecc3ee7 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -41,7 +41,6 @@ class BreakPointHit: public VMException {};
class BadInstruction: public VMException {};
class OutOfGas: public VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
-class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
// 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.
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index fdf1338b3..15727f9c1 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -17,7 +17,7 @@
/** @file Host.cpp
* @authors:
* Gav Wood
- * Eric Lombrozo
+ * Eric Lombrozo (Windows version of populateAddresses())
* @date 2014
*/
@@ -54,55 +54,83 @@ static const set c_rejectAddresses = {
{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_listenPort(_port),
- m_localNetworking(_localNetworking),
- m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
+ m_netPrefs(_n),
+ m_acceptor(m_ioService),
m_socket(m_ioService),
m_id(h512::random())
{
populateAddresses();
- determinePublic(_publicAddress, _upnp);
- ensureAccepting();
m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << m_id.abridged();
+ if (_start)
+ start();
}
-Host::Host(std::string const& _clientVersion, string const& _publicAddress, bool _upnp, bool _localNetworking):
- 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())
+Host::~Host()
{
- m_listenPort = m_acceptor.local_endpoint().port();
-
- // populate addresses.
- populateAddresses();
- determinePublic(_publicAddress, _upnp);
- ensureAccepting();
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
- clog(NetNote) << "Id:" << m_id.abridged();
+ stop();
}
-Host::Host(std::string const& _clientVersion):
- 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())
+void Host::start()
{
- // populate addresses.
- 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_lastPeersRequest = chrono::steady_clock::time_point::min();
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();
+
+ m_ioService.reset();
}
unsigned Host::protocolVersion() const
@@ -284,7 +312,7 @@ std::map Host::potentialPeers()
{
auto ep = j->endpoint();
// Skip peers with a listen port of zero or are on a private network
- bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_localNetworking));
+ bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
}
@@ -293,7 +321,7 @@ std::map Host::potentialPeers()
void Host::ensureAccepting()
{
- if (m_accepting == false)
+ if (!m_accepting)
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true;
@@ -315,7 +343,7 @@ void Host::ensureAccepting()
clog(NetWarn) << "ERROR: " << _e.what();
}
m_accepting = false;
- if (ec.value() != 1)
+ if (ec.value() < 1)
ensureAccepting();
});
}
@@ -325,6 +353,7 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept
{
try
{
+ // TODO: actual DNS lookup.
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port));
}
catch (exception const& e)
@@ -457,11 +486,8 @@ std::vector Host::peers(bool _updatePing) const
return ret;
}
-void Host::process()
+void Host::doWork()
{
- for (auto const& i: m_capabilities)
- if (!i.second->isInitialised())
- return;
growPeers();
prunePeers();
m_ioService.poll();
diff --git a/libp2p/Host.h b/libp2p/Host.h
index 54e8f967e..e8b95e2a8 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include "HostCapability.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@@ -41,22 +42,28 @@ class RLPStream;
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
* 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 HostCapabilityFace;
public:
/// 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);
- /// 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);
+ Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false);
/// Will block on network process events.
virtual ~Host();
@@ -78,11 +85,6 @@ public:
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
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.
bool havePeer(h512 _id) const;
@@ -107,11 +109,17 @@ public:
/// Deserialise the data and populate the set of known peers.
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; }
void registerPeer(std::shared_ptr _s, std::vector const& _caps);
-protected:
+private:
/// Called when the session has provided us with a new peer we can connect to.
void noteNewPeers() {}
@@ -123,12 +131,19 @@ protected:
void growPeers();
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 potentialPeers();
std::string m_clientVersion;
- unsigned short m_listenPort;
- bool m_localNetworking = false;
+ NetworkPreferences m_netPrefs;
+
+ static const int NetworkStopped = -1;
+ int m_listenPort = NetworkStopped;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
diff --git a/libp2p/HostCapability.h b/libp2p/HostCapability.h
index 4b6d38f64..1c532788b 100644
--- a/libp2p/HostCapability.h
+++ b/libp2p/HostCapability.h
@@ -48,7 +48,9 @@ public:
protected:
virtual std::string name() const = 0;
virtual Capability* newPeerCapability(Session* _s) = 0;
- virtual bool isInitialised() const { return true; }
+
+ virtual void onStarting() {}
+ virtual void onStopping() {}
void seal(bytes& _b);
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index 777717371..f117b426e 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -159,7 +159,7 @@ bool Session::interpret(RLP const& _r)
bi::address_v4 peerAddress(_r[i][0].toHash>().asArray());
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt());
h512 id = _r[i][2].toHash();
- if (isPrivateAddress(peerAddress) && !m_server->m_localNetworking)
+ if (isPrivateAddress(peerAddress) && !m_server->m_netPrefs.localNetworking)
goto CONTINUE;
clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")";
diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp
index 689daf8d7..714081dfe 100644
--- a/libqethereum/QEthereum.cpp
+++ b/libqethereum/QEthereum.cpp
@@ -8,41 +8,8 @@
#include
#include "QEthereum.h"
using namespace std;
-
-// types
-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;
+using namespace dev;
+using namespace dev::eth;
dev::bytes toBytes(QString const& _s)
{
@@ -89,7 +56,7 @@ QString unpadded(QString _s)
return _s;
}
-QEthereum::QEthereum(QObject* _p, Client* _c, QList _accounts):
+QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList _accounts):
QObject(_p), m_client(_c), m_accounts(_accounts)
{
// 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());
}
-Client* QEthereum::client() const
+eth::Interface* QEthereum::client() const
{
return m_client;
}
@@ -162,7 +129,7 @@ QString QEthereum::coinbase() 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
@@ -381,7 +348,7 @@ bool QEthereum::isMining() const
bool QEthereum::isListening() const
{
- return m_client ? client()->haveNetwork() : false;
+ return /*m_client ? client()->haveNetwork() :*/ false;
}
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)
return;
- if (_l)
+/* if (_l)
client()->startNetwork();
else
- client()->stopNetwork();
+ client()->stopNetwork();*/
}
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)
diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h
index cacf1cfc4..50f2d96a5 100644
--- a/libqethereum/QEthereum.h
+++ b/libqethereum/QEthereum.h
@@ -7,8 +7,7 @@
#include
namespace dev { namespace eth {
-class Client;
-class State;
+class Interface;
}}
class QJSEngine;
@@ -99,11 +98,11 @@ class QEthereum: public QObject
Q_OBJECT
public:
- QEthereum(QObject* _p, dev::eth::Client* _c, QList _accounts);
+ QEthereum(QObject* _p, dev::eth::Interface* _c, QList _accounts);
virtual ~QEthereum();
- dev::eth::Client* client() const;
- void setClient(dev::eth::Client* _c) { m_client = _c; }
+ dev::eth::Interface* client() const;
+ 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.
void clientDieing();
@@ -199,7 +198,7 @@ private:
Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged)
Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault)
- dev::eth::Client* m_client;
+ dev::eth::Interface* m_client;
std::vector m_watches;
QList m_accounts;
};
diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp
index 350427f3e..89578a29a 100644
--- a/libqethereum/QmlEthereum.cpp
+++ b/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.
dev::eth::Client* g_qmlClient;
QObject* g_qmlMain;
-
+#if 0
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);
}
+#endif
+
// extra bits needed to link on VS
#ifdef _MSC_VER
diff --git a/libqethereum/QmlEthereum.h b/libqethereum/QmlEthereum.h
index dcb636301..d242540a1 100644
--- a/libqethereum/QmlEthereum.h
+++ b/libqethereum/QmlEthereum.h
@@ -23,8 +23,8 @@ Q_DECLARE_METATYPE(dev::u256)
Q_DECLARE_METATYPE(dev::Address)
Q_DECLARE_METATYPE(dev::Secret)
Q_DECLARE_METATYPE(dev::KeyPair)
-Q_DECLARE_METATYPE(QmlAccount*)
-Q_DECLARE_METATYPE(QmlEthereum*)
+//Q_DECLARE_METATYPE(QmlAccount*)
+//Q_DECLARE_METATYPE(QmlEthereum*)
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 toAbridged(dev::Address _a) const { return QString::fromStdString(_a.abridged()); }
};
-
+#if 0
class QmlAccount: public QObject
{
Q_OBJECT
@@ -155,7 +155,7 @@ private:
Q_PROPERTY(bool listening READ isListening WRITE setListening)
Q_PROPERTY(bool mining READ isMining WRITE setMining)
};
-
+#endif
#if 0
template 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 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)); }
diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp
index 93f81dd0a..55e82a36f 100644
--- a/libwebthree/WebThree.cpp
+++ b/libwebthree/WebThree.cpp
@@ -35,102 +35,50 @@ using namespace dev::p2p;
using namespace dev::eth;
using namespace dev::shh;
-WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set 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 const& _interfaces, NetworkPreferences const& _n):
m_clientVersion(_clientVersion),
- m_net(m_clientVersion, _listenPort, _publicIP, _upnp, _localNetworking)
+ m_net(_clientVersion, _n)
{
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
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"))
// 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()
{
- 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 WebThreeDirect::peers()
{
- ReadGuard l(x_work);
return m_net.peers();
}
size_t WebThreeDirect::peerCount() const
{
- ReadGuard l(x_work);
return m_net.peerCount();
}
void WebThreeDirect::setIdealPeerCount(size_t _n)
{
- ReadGuard l(x_work);
return m_net.setIdealPeerCount(_n);
}
bytes WebThreeDirect::savePeers()
{
- ReadGuard l(x_work);
return m_net.savePeers();
}
void WebThreeDirect::restorePeers(bytesConstRef _saved)
{
- ReadGuard l(x_work);
return m_net.restorePeers(_saved);
}
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)
{
- ReadGuard l(x_work);
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));
-}
-
diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h
index cf02c3122..06717ee26 100644
--- a/libwebthree/WebThree.h
+++ b/libwebthree/WebThree.h
@@ -66,7 +66,7 @@ class WebThreeDirect
public:
/// 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*.
- WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set 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 const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences());
/// Destructor.
~WebThreeDirect();
@@ -104,25 +104,23 @@ public:
/// Sets the ideal number of peers.
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.
- void startNetwork() { setIdealPeerCount(5); }
+ void startNetwork() { m_net.start(); }
/// Stop the network subsystem.
- void stopNetwork() { setIdealPeerCount(0); }
+ void stopNetwork() { m_net.stop(); }
private:
- /// Do some work on the network.
- void workNet();
-
std::string m_clientVersion; ///< Our end-application client's name/version.
std::unique_ptr m_ethereum; ///< Main interface for Ethereum ("eth") protocol.
std::unique_ptr 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.
- std::unique_ptr m_work; ///< The network thread.
- mutable boost::shared_mutex x_work; ///< Lock for the network existance.
- std::atomic m_workState;
};
@@ -137,7 +135,7 @@ class RPCMaster {};
class EthereumSlave: public eth::Interface
{
public:
- EthereumSlave(RPCSlave* _c) {}
+ EthereumSlave(RPCSlave*) {}
// TODO: implement all of the virtuals with the RLPClient link.
};
@@ -145,7 +143,7 @@ public:
class EthereumMaster
{
public:
- EthereumMaster(RPCMaster* _m) {}
+ EthereumMaster(RPCMaster*) {}
// TODO: implement the master-end of whatever the RLPClient link will send over.
};
@@ -155,7 +153,7 @@ public:
class WhisperSlave: public shh::Interface
{
public:
- WhisperSlave(RPCSlave* _c) {}
+ WhisperSlave(RPCSlave*) {}
// TODO: implement all of the virtuals with the RLPClient link.
};
@@ -163,7 +161,7 @@ public:
class WhisperMaster
{
public:
- WhisperMaster(RPCMaster* _m) {}
+ WhisperMaster(RPCMaster*) {}
// TODO: implement the master-end of whatever the RLPClient link will send over.
};
diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp
index 02a883dbc..20c42a9b8 100644
--- a/test/TestHelper.cpp
+++ b/test/TestHelper.cpp
@@ -42,11 +42,14 @@ void mine(Client& c, int numBlocks)
void connectClients(Client& c1, Client& c2)
{
+ // TODO: Move to WebThree. eth::Client no longer handles networking.
+#if 0
short c1Port = 20000;
short c2Port = 21000;
c1.startNetwork(c1Port);
c2.startNetwork(c2Port);
c2.connect("127.0.0.1", c1Port);
+#endif
}
}
diff --git a/test/peer.cpp b/test/peer.cpp
index 821aab514..a99ce7201 100644
--- a/test/peer.cpp
+++ b/test/peer.cpp
@@ -46,7 +46,7 @@ int peerTest(int argc, char** argv)
remoteHost = argv[i];
}
- Host ph("Test", listenPort);
+ Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty())
ph.connect(remoteHost, remotePort);
diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt
index a68b90813..77b2bb496 100644
--- a/third/CMakeLists.txt
+++ b/third/CMakeLists.txt
@@ -52,7 +52,7 @@ else ()
endif ()
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)
# First have qt5 install plugins and frameworks
diff --git a/third/MainWin.cpp b/third/MainWin.cpp
index 7bbdd721b..5e147bbda 100644
--- a/third/MainWin.cpp
+++ b/third/MainWin.cpp
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -38,49 +39,14 @@
#include
#include
#include
+#include
#include "BuildInfo.h"
#include "MainWin.h"
#include "ui_Main.h"
using namespace std;
-
-// types
-using dev::bytes;
-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;
+using namespace dev;
+using namespace dev::eth;
+using namespace dev::p2p;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
{
@@ -133,12 +99,12 @@ Main::Main(QWidget *parent) :
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"}));
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// 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();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
@@ -181,6 +147,11 @@ Main::~Main()
writeSettings();
}
+eth::Client* Main::ethereum() const
+{
+ return m_web3->ethereum();
+}
+
void Main::onKeysChanged()
{
installBalancesWatch();
@@ -188,14 +159,14 @@ void Main::onKeysChanged()
unsigned Main::installWatch(dev::eth::MessageFilter const& _tf, std::function const& _f)
{
- auto ret = m_client->installWatch(_tf);
+ auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f;
return ret;
}
unsigned Main::installWatch(dev::h256 _tf, std::function const& _f)
{
- auto ret = m_client->installWatch(_tf);
+ auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f;
return ret;
}
@@ -209,14 +180,14 @@ void Main::installWatches()
void Main::installNameRegWatch()
{
- m_client->uninstallWatch(m_nameRegFilter);
- m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)m_client->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
+ ethereum()->uninstallWatch(m_nameRegFilter);
+ m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
}
void Main::installCurrenciesWatch()
{
- m_client->uninstallWatch(m_currenciesFilter);
- m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)m_client->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
+ ethereum()->uninstallWatch(m_currenciesFilter);
+ m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
}
void Main::installBalancesWatch()
@@ -224,9 +195,9 @@ void Main::installBalancesWatch()
dev::eth::MessageFilter tf;
vector altCoins;
- Address coinsAddr = right160(m_client->stateAt(c_config, 1));
- for (unsigned i = 0; i < m_client->stateAt(coinsAddr, 0); ++i)
- altCoins.push_back(right160(m_client->stateAt(coinsAddr, i + 1)));
+ Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
+ for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
+ altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys)
{
tf.altered(i.address());
@@ -234,7 +205,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address());
}
- m_client->uninstallWatch(m_balancesFilter);
+ ethereum()->uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
}
@@ -295,8 +266,8 @@ QString Main::pretty(dev::Address _a) const
{
h256 n;
- if (h160 nameReg = (u160)m_client->stateAt(c_config, 0))
- n = m_client->stateAt(nameReg, (u160)(_a));
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
+ n = ethereum()->stateAt(nameReg, (u160)(_a));
return fromRaw(n);
}
@@ -322,8 +293,8 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size())
{
- if (h160 nameReg = (u160)m_client->stateAt(c_config, 0))
- if (h256 a = m_client->stateAt(nameReg, n))
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
+ if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
}
if (_a.size() == 40)
@@ -351,11 +322,11 @@ QString Main::lookup(QString const& _a) const
*/
h256 ret;
- if (h160 dnsReg = (u160)m_client->stateAt(c_config, 4, 0))
- ret = m_client->stateAt(dnsReg, n);
+ if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
+ ret = ethereum()->stateAt(dnsReg, n);
/* if (!ret)
- if (h160 nameReg = (u160)m_client->stateAt(c_config, 0, 0))
- ret = m_client->stateAt(nameReg, n2);
+ if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0))
+ ret = ethereum()->stateAt(nameReg, n2);
*/
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]);
@@ -385,7 +356,7 @@ void Main::writeSettings()
s.setValue("address", b);
s.setValue("url", ui->urlEdit->text());
- bytes d = m_client->savePeers();
+ bytes d = m_web3->savePeers();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers);
@@ -416,7 +387,7 @@ void Main::readSettings(bool _skipGeometry)
m_myKeys.append(KeyPair(k));
}
}
- m_client->setAddress(m_myKeys.back().address());
+ ethereum()->setAddress(m_myKeys.back().address());
m_peers = s.value("peers").toByteArray();
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed();
@@ -466,8 +437,8 @@ void Main::on_urlEdit_returnPressed()
void Main::refreshMining()
{
- dev::eth::MineProgress p = m_client->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");
+ dev::eth::MineProgress p = ethereum()->miningProgress();
+ 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()
@@ -477,18 +448,18 @@ void Main::refreshBalances()
ui->ourAccounts->clear();
u256 totalBalance = 0;
map> altCoins;
- Address coinsAddr = right160(m_client->stateAt(c_config, 1));
- for (unsigned i = 0; i < m_client->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);
+ Address coinsAddr = right160(ethereum()->stateAt(c_config, 1));
+ for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
+ altCoins[right160(ethereum()->stateAt(coinsAddr, ethereum()->stateAt(coinsAddr, i + 1)))] = make_pair(fromRaw(ethereum()->stateAt(coinsAddr, i + 1)), 0);
for (auto i: m_myKeys)
{
- u256 b = m_client->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))
+ u256 b = ethereum()->balanceAt(i.address());
+ (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));
totalBalance += b;
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;
@@ -500,7 +471,7 @@ void Main::refreshBalances()
void Main::refreshNetwork()
{
- auto ps = m_client->peers();
+ auto ps = m_web3->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
}
@@ -514,8 +485,8 @@ void Main::refreshAll()
void Main::refreshBlockCount()
{
cwatch << "refreshBlockCount()";
- auto d = m_client->blockChain().details();
- auto diff = BlockInfo(m_client->blockChain().block()).difficulty;
+ auto d = ethereum()->blockChain().details();
+ 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));
}
@@ -543,7 +514,7 @@ void Main::timerEvent(QTimerEvent*)
m_ethereum->poll();
for (auto const& i: m_handlers)
- if (m_client->checkWatch(i.first))
+ if (ethereum()->checkWatch(i.first))
i.second();
}
@@ -574,7 +545,7 @@ void Main::ensureNetwork()
{
string n = string("Third/v") + dev::Version;
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();
string defPeer;
@@ -583,13 +554,16 @@ void Main::ensureNetwork()
else if (pocnumber == 6)
defPeer = "54.76.56.74";
- if (!m_client->haveNetwork())
- m_client->startNetwork(30303, defPeer);
+ if (!web3()->haveNetwork())
+ {
+ web3()->startNetwork();
+ web3()->connect(defPeer);
+ }
else
- if (!m_client->peerCount())
- m_client->connect(defPeer);
+ if (!m_web3->peerCount())
+ m_web3->connect(defPeer);
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()
@@ -600,7 +574,7 @@ void Main::on_connect_triggered()
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
- m_client->connect(host, port);
+ web3()->connect(host, port);
}
}
@@ -608,11 +582,11 @@ void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
- m_client->setAddress(m_myKeys.last().address());
- m_client->startMining();
+ ethereum()->setAddress(m_myKeys.last().address());
+ ethereum()->startMining();
}
else
- m_client->stopMining();
+ ethereum()->stopMining();
}
// extra bits needed to link on VS
diff --git a/third/MainWin.h b/third/MainWin.h
index 76505d603..df05d6828 100644
--- a/third/MainWin.h
+++ b/third/MainWin.h
@@ -36,7 +36,8 @@ namespace Ui {
class Main;
}
-namespace dev { namespace eth {
+namespace dev { class WebThreeDirect;
+namespace eth {
class Client;
class State;
class MessageFilter;
@@ -52,7 +53,8 @@ public:
explicit Main(QWidget *parent = 0);
~Main();
- dev::eth::Client* client() { return m_client.get(); }
+ dev::WebThreeDirect* web3() const { return m_web3.get(); }
+ dev::eth::Client* ethereum() const;
QList const& owned() const { return m_myKeys; }
@@ -111,7 +113,7 @@ private:
std::unique_ptr ui;
- std::unique_ptr m_client;
+ std::unique_ptr m_web3;
QList m_myKeys;
diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp
index ade04c4fa..3fa5a9388 100644
--- a/walleth/MainWin.cpp
+++ b/walleth/MainWin.cpp
@@ -61,7 +61,7 @@ Main::Main(QWidget *parent) :
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();