diff --git a/BUILDING.md b/BUILDING.md
deleted file mode 100644
index 56174cbf8..000000000
--- a/BUILDING.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Building Ethereum
-
-## Dependencies
-
-secp256k1 implementation: https://github.com/sipa/secp256k1.git
-Expects secp256k1 directory to be in same path as cpp-ethereum.
-
-(NOTE: secp256k1 requires a development installation of the GMP library, libssl and libcrypto++.)
-
-libcrypto++, version 5.6.2 or greater (i.e. with SHA3 support). Because it's so recent, it expects this to be built in a directory libcrypto562 in the same path as cpp-ethereum. A recent version of Boost (I use version 1.53) and leveldb (I use version 1.9.0).
-
-A decent C++11 compiler (I use GNU GCC 4.8.1). CMake, version 2.8 or greater.
-
-On Ubuntu:
-
- sudo apt-get install libgmp3-dev libcrypto++-dev libssl-dev libboost-all-dev cmake libleveldb-dev libminiupnpc-dev
-
-## Building
-
- mkdir /path/to/cpp-ethereum/../cpp-ethereum-build
- cd /path/to/cpp-ethereum-build
- cmake -DCMAKE_BUILD_TYPE=Debug /path/to/cpp-ethereum
- make
-
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 79d3285ab..62ed5d6d3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,15 +5,32 @@ set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
-set(ETH_VERSION 0.1.1)
-
+set(ETH_VERSION 0.1.2)
+set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE})
+set(ETH_BUILD_PLATFORM ${CMAKE_SYSTEM_NAME})
+if (CMAKE_COMPILER_IS_MINGW)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw")
+elseif (CMAKE_COMPILER_IS_MSYS)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msys")
+elseif (CMAKE_COMPILER_IS_GNUCXX)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/g++")
+elseif (CMAKE_COMPILER_IS_MSVC)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msvc")
+else ()
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown")
+endif ()
# Initialize CXXFLAGS.
-set(CMAKE_CXX_FLAGS "-Wall -std=c++11 -DETH_VERSION=${ETH_VERSION}")
+set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+add_definitions("-DETH_VERSION=${ETH_VERSION}")
+add_definitions("-DETH_BUILD_TYPE=${ETH_BUILD_TYPE}")
+add_definitions("-DETH_BUILD_PLATFORM=${ETH_BUILD_PLATFORM}")
+#set(CMAKE_CXX_FLAGS, "${CMAKE_CXX_FLAGS} -DETH_VERSION=${ETH_VERSION} -DETH_BUILD_TYPE=${ETH_BUILD_TYPE} -DETH_BUILD_PLATFORM=${ETH_BUILD_PLATFORM}")
+
# Compiler-specific C++11 activation.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
execute_process(
diff --git a/CodingStandards.txt b/CodingStandards.txt
index 727e53efb..79403af2f 100644
--- a/CodingStandards.txt
+++ b/CodingStandards.txt
@@ -46,7 +46,7 @@ a. File comment is always at top, and includes:
- Original author, date.
- Later maintainers (not contributors - they can be seen through VCS log).
- Copyright.
-- Licence (e.g. see COPYING).
+- License (e.g. see COPYING).
b. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment.
c. Prefer static const variable to value macros.
d. Prefer inline constexpr functions to function macros.
diff --git a/README.md b/README.md
index bd45e5fb1..a3c7622f6 100644
--- a/README.md
+++ b/README.md
@@ -6,18 +6,16 @@ Gav Wood, 2014.
## Building
-See BUILDING.md
+See https://github.com/ethereum/cpp-ethereum/wiki/Building and https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips .
## Yet To Do
See TODO
-## Licence
+## License
-See LICENCE
+See LICENSE
## Contributing
Please read CodingStandards.txt thoroughly before making alterations to the code base. Please do *NOT* use an editor that automatically reformats whitespace away from astylerc or the formating guidelines as describled in CodingStandards.txt.
-
-
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 3723e1e23..67dfa163e 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -91,9 +91,16 @@
+
+
@@ -132,44 +139,77 @@
2
-
-
- 4
-
+
0
-
-
-
- QFrame::NoFrame
+
+
+ Qt::Vertical
+
+
+ QFrame::NoFrame
+
+
+
+
+
-
+
+
+ Listen on
+
+
+
+ -
+
+
+ 1
+
+
+ 5
+
+
+
+ -
+
+
+ Ideal Peers
+
+
+
+ -
+
+
+ 1024
+
+
+ 32767
+
+
+ 30303
+
+
+
+ -
+
+
+ Client Name
+
+
+
+ -
+
+
+ Anonymous
+
+
+
+
+
- -
-
-
-
-
-
- Listen on
-
-
-
- -
-
-
- 1024
-
-
- 32767
-
-
- 30303
-
-
-
-
-
@@ -207,7 +247,7 @@
10
- 4
+ 1
Qt::Vertical
@@ -270,7 +310,7 @@
- 349
+ 408
251
@@ -291,26 +331,6 @@
4
- -
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
- Send
-
-
-
- -
-
-
-
@@ -318,6 +338,9 @@
+ -
+
+
-
@@ -331,6 +354,16 @@
+ -
+
+
+ Data
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
-
@@ -344,44 +377,45 @@
- -
-
-
-
-
-
-
-
-
- 430000000
-
-
- 100
+
-
+
+
+ -
+
+
+ Send
- -
-
-
- -
-
-
- Fee
+
-
+
+
+
+ 1
+ 0
+
+
+
+ (Create Contract)
- -
-
+
-
+
- Data
+
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
+
-
+
+
+
+
+
@@ -459,6 +493,11 @@
&New Address
+
+
+ &About...
+
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 9e0d3fc0c..273ccd871 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -15,7 +15,8 @@ static void initUnits(QComboBox* _b)
_b->setCurrentIndex(6);
}
-#define ETH_QUOTED(A) #A
+#define ADD_QUOTES_HELPER(s) #s
+#define ADD_QUOTES(s) ADD_QUOTES_HELPER(s)
Main::Main(QWidget *parent) :
QMainWindow(parent),
@@ -23,10 +24,8 @@ Main::Main(QWidget *parent) :
{
setWindowFlags(Qt::Window);
ui->setupUi(this);
- initUnits(ui->valueUnits);
- initUnits(ui->feeUnits);
g_logPost = [=](std::string const& s, char const*) { ui->log->addItem(QString::fromStdString(s)); };
- m_client = new Client("AlethZero/v" ETH_QUOTED(ETH_VERSION));
+ m_client = new Client("AlethZero");
readSettings();
refresh();
@@ -42,7 +41,7 @@ Main::Main(QWidget *parent) :
{
m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts);
});
- QNetworkRequest r(QUrl("http://www.ethereum.org/servers.txt"));
+ QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc2.txt"));
r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36");
m_webCtrl.get(r);
srand(time(0));
@@ -50,6 +49,7 @@ Main::Main(QWidget *parent) :
on_verbosity_sliderMoved();
+ initUnits(ui->valueUnits);
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->blockChain);
@@ -62,6 +62,11 @@ Main::~Main()
delete ui;
}
+void Main::on_about_triggered()
+{
+ QMessageBox::about(this, "About AlethZero PoC-2", "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Subtly and several others.");
+}
+
void Main::writeSettings()
{
QSettings s("ethereum", "alethzero");
@@ -131,9 +136,8 @@ void Main::refresh()
for (pair const& i: m_client->transactionQueue().transactions())
{
Transaction t(i.second);
- ui->transactionQueue->addItem(QString("%1 (%2 fee) @ %3 <- %4")
+ ui->transactionQueue->addItem(QString("%1 @ %2 <- %3")
.arg(formatBalance(t.value).c_str())
- .arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().asArray()).c_str()) );
}
@@ -147,9 +151,8 @@ void Main::refresh()
for (auto const& i: RLP(bc.block(h))[1])
{
Transaction t(i.data());
- ui->transactions->addItem(QString("%1 (%2) @ %3 <- %4")
+ ui->transactions->addItem(QString("%1 @ %2 <- %3")
.arg(formatBalance(t.value).c_str())
- .arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().asArray()).c_str()) );
}
@@ -168,6 +171,12 @@ void Main::refresh()
m_client->unlock();
}
+void Main::on_idealPeers_valueChanged()
+{
+ if (m_client->peerServer())
+ m_client->peerServer()->setIdealPeerCount(ui->idealPeers->value());
+}
+
void Main::on_ourAccounts_doubleClicked()
{
qApp->clipboard()->setText(ui->ourAccounts->currentItem()->text().section(" @ ", 1));
@@ -183,11 +192,62 @@ void Main::on_accounts_doubleClicked()
qApp->clipboard()->setText(ui->accounts->currentItem()->text().section(" @ ", 1));
}
+void Main::on_destination_textChanged()
+{
+ updateFee();
+}
+
+void Main::on_data_textChanged()
+{
+ m_data = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"), QString::SkipEmptyParts);
+ updateFee();
+}
+
+u256 Main::fee() const
+{
+ return (ui->destination->text().isEmpty() || !ui->destination->text().toInt()) ? m_client->state().fee(m_data.size()) : m_client->state().fee();
+}
+
+u256 Main::value() const
+{
+ return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
+}
+
+u256 Main::total() const
+{
+ return value() + fee();
+}
+
+void Main::updateFee()
+{
+ ui->fee->setText(QString("(fee: %1)").arg(formatBalance(fee()).c_str()));
+ auto totalReq = total();
+ ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
+
+ bool ok = false;
+ for (auto i: m_myKeys)
+ if (m_client->state().balance(i.address()) >= totalReq)
+ {
+ ok = true;
+ break;
+ }
+ ui->send->setEnabled(ok);
+ QPalette p = ui->total->palette();
+ p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00));
+ ui->total->setPalette(p);
+}
+
void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
+ ui->clientName->setEnabled(!ui->net->isChecked());
+ string n = "AlethZero/v" ADD_QUOTES(ETH_VERSION);
+ if (ui->clientName->text().size())
+ n += "/" + ui->clientName->text().toStdString();
+ n += "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM);
+ m_client->setClientVersion(n);
if (ui->net->isChecked())
- m_client->startNetwork(ui->port->value(), string(), 0, NodeMode::Full, 5, std::string(), ui->upnp->isChecked());
+ m_client->startNetwork(ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), std::string(), ui->upnp->isChecked());
else
m_client->stopNetwork();
}
@@ -227,9 +287,7 @@ void Main::on_mine_triggered()
void Main::on_send_clicked()
{
- u256 value = ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
- u256 fee = ui->fee->value() * units()[units().size() - 1 - ui->feeUnits->currentIndex()].first;
- u256 totalReq = value + fee;
+ u256 totalReq = value() + fee();
m_client->lock();
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
@@ -237,12 +295,11 @@ void Main::on_send_clicked()
m_client->unlock();
Secret s = m_myKeys.front().secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString()));
- auto ds = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"));
u256s data;
- data.reserve(ds.size());
- for (QString const& i: ds)
+ data.reserve(m_data.size());
+ for (QString const& i: m_data)
data.push_back(u256(i.toStdString()));
- m_client->transact(s, r, value, fee, data);
+ m_client->transact(s, r, value(), data);
refresh();
return;
}
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 29be9733c..7f9cd16cf 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -32,15 +32,26 @@ private slots:
void on_verbosity_sliderMoved();
void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked();
+ void on_destination_textChanged();
+ void on_data_textChanged();
+ void on_idealPeers_valueChanged();
+ void on_value_valueChanged() { updateFee(); }
+ void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_log_doubleClicked();
+ void on_about_triggered();
void on_quit_triggered() { close(); }
void refresh();
private:
+ void updateFee();
void readSettings();
void writeSettings();
+ eth::u256 fee() const;
+ eth::u256 total() const;
+ eth::u256 value() const;
+
Ui::Main *ui;
eth::Client* m_client;
@@ -49,6 +60,7 @@ private:
QTimer* m_refresh;
QStringList m_servers;
QVector m_myKeys;
+ QStringList m_data;
QNetworkAccessManager m_webCtrl;
};
diff --git a/alethzero/alephzero.pro b/alethzero/alephzero.pro
deleted file mode 100644
index 4b58d56ae..000000000
--- a/alethzero/alephzero.pro
+++ /dev/null
@@ -1,42 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2014-01-22T11:47:38
-#
-#-------------------------------------------------
-
-QT += core gui widgets network
-
-
-TARGET = alephzero
-TEMPLATE = app
-
-CONFIG(debug, debug|release): DEFINES += ETH_DEBUG
-
-QMAKE_CXXFLAGS += -std=c++11
-
-#CONFIG += local_cryptopp
-
-local_cryptopp {
- QMAKE_LIBDIR += ../../cryptopp562
- CRYPTOPP_LIBS += -lcryptopp
-}
-
-!local_cryptopp {
- CRYPTOPP_LIBS += -lcryptoppeth
-}
-
-INCLUDEPATH += ../../cpp-ethereum
-QMAKE_LIBDIR += ../../cpp-ethereum-build/libethereum ../../cpp-ethereum-build/secp256k1
-CONFIG(debug, debug|release): LIBS += -Wl,-rpath,../../cpp-ethereum-build/libethereum
-LIBS += -lethereum $${CRYPTOPP_LIBS} -lsecp256k1 -lminiupnpc -lleveldb -lgmp -lboost_filesystem -lboost_system
-
-SOURCES += main.cpp \
- MainWin.cpp
-
-HEADERS += \
- MainWin.h
-
-FORMS += Main.ui
-
-
-
diff --git a/eth/main.cpp b/eth/main.cpp
index 04e4871b3..6c3b4bed7 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -20,6 +20,8 @@
* Ethereum client.
*/
+#include
+#include
#include
#include "Defaults.h"
#include "Client.h"
@@ -30,6 +32,9 @@
using namespace std;
using namespace eth;
+#define ADD_QUOTES_HELPER(s) #s
+#define ADD_QUOTES(s) ADD_QUOTES_HELPER(s)
+
bytes contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
@@ -163,7 +168,7 @@ int main(int argc, char** argv)
remoteHost = argv[i];
}
- Client c("Ethereum(++)/v0.1", coinbase, dbPath);
+ Client c("Ethereum(++)/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM), coinbase, dbPath);
if (interactive)
{
cout << "Ethereum (++)" << endl;
@@ -205,20 +210,18 @@ int main(int argc, char** argv)
string sechex;
string rechex;
u256 amount;
- u256 fee;
- cin >> sechex >> rechex >> amount >> fee;
+ cin >> sechex >> rechex >> amount;
Secret secret = h256(fromUserHex(sechex));
Address dest = h160(fromUserHex(rechex));
- c.transact(secret, dest, amount, fee);
+ c.transact(secret, dest, amount);
}
else if (cmd == "send")
{
string rechex;
u256 amount;
- u256 fee;
- cin >> rechex >> amount >> fee;
+ cin >> rechex >> amount;
Address dest = h160(fromUserHex(rechex));
- c.transact(us.secret(), dest, amount, fee);
+ c.transact(us.secret(), dest, amount);
}
else if (cmd == "exit")
{
@@ -236,7 +239,7 @@ int main(int argc, char** argv)
c.stopMining();
else
c.startMining();
- usleep(100000);
+ this_thread::sleep_for(chrono::milliseconds(100));
}
}
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index c1204b2ce..9e624b2cb 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -124,20 +124,20 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
auto newHash = eth::sha3(_block);
+ clog(BlockChainChat) << "Attempting import of " << newHash << "...";
+
// Check block doesn't already exist first!
if (details(newHash))
{
-// cout << " Not new." << endl;
+ clog(BlockChainChat) << " Not new.";
throw AlreadyHaveBlock();
}
- cnote << "Attempting import of " << newHash << "...";
-
// Work out its number as the parent's number + 1
auto pd = details(bi.parentHash);
if (!pd)
{
- cwarn << " Unknown parent " << bi.parentHash;
+ clog(BlockChainNote) << " 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();
}
@@ -177,12 +177,11 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
{
m_lastBlockHash = newHash;
m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
- cnote << " Imported and best.";
+ clog(BlockChainNote) << " Imported and best.";
}
else
{
- cnote << " Imported.";
-// cwarn << "Imported block not newest (otd=" << m_details[m_lastBlockHash].totalDifficulty << ", td=" << td << ")";
+ clog(BlockChainNote) << " Imported but not best (oTD:" << m_details[m_lastBlockHash].totalDifficulty << ", TD:" << td << ")";
}
}
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
index 61339dbb7..919b8ba54 100644
--- a/libethereum/BlockChain.h
+++ b/libethereum/BlockChain.h
@@ -22,6 +22,7 @@
#pragma once
#include "Common.h"
+#include "AddressState.h"
namespace ldb = leveldb;
namespace eth
@@ -54,6 +55,10 @@ class Overlay;
class AlreadyHaveBlock: public std::exception {};
class UnknownParent: public std::exception {};
+struct BlockChainChat: public LogChannel { static const char constexpr* name = "-B-"; static const int verbosity = 7; };
+struct BlockChainNote: public LogChannel { static const char constexpr* name = "=B="; static const int verbosity = 1; };
+struct BlockChainWarn: public LogChannel { static const char constexpr* name = "!B!"; static const int verbosity = 0; };
+
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
*/
@@ -91,6 +96,10 @@ public:
h256 genesisHash() const { return m_genesisHash; }
+ std::vector> interestQueue() { std::vector> ret; swap(ret, m_interestQueue); return ret; }
+ void pushInterest(Address _a) { m_interest[_a]++; }
+ void popInterest(Address _a) { if (m_interest[_a] > 1) m_interest[_a]--; else if (m_interest[_a]) m_interest.erase(_a); }
+
private:
void checkConsistency();
@@ -98,6 +107,10 @@ private:
mutable std::map m_details;
mutable std::map m_cache;
+ /// The queue of transactions that have happened that we're interested in.
+ std::map m_interest;
+ std::vector> m_interestQueue;
+
ldb::DB* m_db;
ldb::DB* m_detailsDB;
diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp
index 3146ffe44..520b2c202 100644
--- a/libethereum/BlockInfo.cpp
+++ b/libethereum/BlockInfo.cpp
@@ -39,6 +39,13 @@ BlockInfo::BlockInfo(bytesConstRef _block)
populate(_block);
}
+BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
+{
+ BlockInfo ret;
+ ret.populateFromHeader(RLP(_block));
+ return ret;
+}
+
bytes BlockInfo::createGenesisBlock()
{
RLPStream block(3);
@@ -79,30 +86,36 @@ void BlockInfo::populateGenesis()
populate(&genesisBlock);
}
-void BlockInfo::populate(bytesConstRef _block)
+void BlockInfo::populateFromHeader(RLP const& _header)
{
- RLP root(_block);
int field = 0;
- RLP header = root[0];
- if (!header.isList())
- throw InvalidBlockFormat(0, header.data());
try
{
- hash = eth::sha3(_block);
- parentHash = header[field = 0].toHash();
- sha3Uncles = header[field = 1].toHash();
- coinbaseAddress = header[field = 2].toHash();
- stateRoot = header[field = 3].toHash();
- sha3Transactions = header[field = 4].toHash();
- difficulty = header[field = 5].toInt();
- timestamp = header[field = 6].toInt();
- extraData = header[field = 7].toBytes();
- nonce = header[field = 8].toHash();
+ parentHash = _header[field = 0].toHash();
+ sha3Uncles = _header[field = 1].toHash();
+ coinbaseAddress = _header[field = 2].toHash();
+ stateRoot = _header[field = 3].toHash();
+ sha3Transactions = _header[field = 4].toHash();
+ difficulty = _header[field = 5].toInt();
+ timestamp = _header[field = 6].toInt();
+ extraData = _header[field = 7].toBytes();
+ nonce = _header[field = 8].toHash();
}
catch (RLP::BadCast)
{
- throw InvalidBlockHeaderFormat(field, header[field].data());
+ throw InvalidBlockHeaderFormat(field, _header[field].data());
}
+}
+
+void BlockInfo::populate(bytesConstRef _block)
+{
+ hash = eth::sha3(_block);
+
+ RLP root(_block);
+ RLP header = root[0];
+ if (!header.isList())
+ throw InvalidBlockFormat(0, header.data());
+ populateFromHeader(header);
if (!root[1].isList())
throw InvalidBlockFormat(1, root[1].data());
diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h
index d932f63de..26d5497a9 100644
--- a/libethereum/BlockInfo.h
+++ b/libethereum/BlockInfo.h
@@ -44,6 +44,8 @@ public:
BlockInfo();
explicit BlockInfo(bytesConstRef _block);
+ static BlockInfo fromHeader(bytesConstRef _block);
+
explicit operator bool() const { return timestamp != Invalid256; }
bool operator==(BlockInfo const& _cmp) const
@@ -61,6 +63,7 @@ public:
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
static BlockInfo const& genesis() { if (!s_genesis) (s_genesis = new BlockInfo)->populateGenesis(); return *s_genesis; }
+ void populateFromHeader(RLP const& _header);
void populate(bytesConstRef _block);
void verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const;
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index ea9c6b3bc..a3ef271e6 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -21,6 +21,8 @@
#include "Client.h"
+#include
+#include
#include "Common.h"
#include "Defaults.h"
using namespace std;
@@ -30,7 +32,8 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
m_clientVersion(_clientVersion),
m_bc(_dbPath),
m_stateDB(State::openDB(_dbPath)),
- m_s(_us, m_stateDB)
+ m_s(_us, m_stateDB),
+ m_mined(_us, m_stateDB)
{
Defaults::setDBPath(_dbPath);
@@ -41,18 +44,18 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
m_s.sync(m_tq);
m_changed = true;
- static std::string thread_name = "eth";
+ static const char* c_threadName = "eth";
#if defined(__APPLE__)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
- m_work = dispatch_queue_create(thread_name.c_str(), DISPATCH_QUEUE_SERIAL);
+ m_work = dispatch_queue_create(c_threadName, DISPATCH_QUEUE_SERIAL);
});
dispatch_async(m_work, ^{
#else
m_work = new thread([&](){
- setThreadName(thread_name);
+ setThreadName(c_threadName);
#endif
while (m_workState != Deleting) work(); m_workState = Deleted;
@@ -64,7 +67,7 @@ Client::~Client()
if (m_workState == Active)
m_workState = Deleting;
while (m_workState != Deleted)
- usleep(10000);
+ this_thread::sleep_for(chrono::milliseconds(10));
}
void Client::startNetwork(short _listenPort, std::string const& _seedHost, short _port, NodeMode _mode, unsigned _peers, string const& _publicIP, bool _upnp)
@@ -93,6 +96,7 @@ void Client::stopNetwork()
void Client::startMining()
{
m_doMine = true;
+ m_miningStarted = true;
}
void Client::stopMining()
@@ -100,14 +104,13 @@ void Client::stopMining()
m_doMine = false;
}
-void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data)
+void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data)
{
m_lock.lock();
Transaction t;
t.nonce = m_s.transactionsFrom(toAddress(_secret));
t.receiveAddress = _dest;
t.value = _amount;
- t.fee = _fee;
t.data = _data;
t.sign(_secret);
m_tq.attemptImport(t.rlp());
@@ -118,12 +121,14 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u2
void Client::work()
{
m_lock.lock();
+ bool changed = false;
+
// 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.
if (m_net)
if (m_net->process(m_bc, m_tq, m_stateDB))
- m_changed = true;
+ changed = true;
// Synchronise state to block chain.
// This should remove any transactions on our queue that are included within our state.
@@ -133,16 +138,25 @@ void Client::work()
// all blocks.
// Resynchronise state with block chain & trans
if (m_s.sync(m_bc))
- m_changed = true;
- if (m_s.sync(m_tq))
- m_changed = true;
+ {
+ changed = true;
+ m_mined = m_s;
+ }
m_lock.unlock();
if (m_doMine)
{
+ if (m_miningStarted)
+ {
+ m_mined = m_s;
+ m_mined.sync(m_tq);
+ m_mined.commitToMine(m_bc);
+ }
+
+ m_miningStarted = false;
+
// Mine for a while.
- m_s.commitToMine(m_bc);
- MineInfo mineInfo = m_s.mine(100);
+ MineInfo mineInfo = m_mined.mine(100);
m_mineProgress.best = max(m_mineProgress.best, mineInfo.best);
m_mineProgress.current = mineInfo.best;
m_mineProgress.requirement = mineInfo.requirement;
@@ -151,14 +165,17 @@ void Client::work()
{
// Import block.
m_lock.lock();
- m_bc.attemptImport(m_s.blockData(), m_stateDB);
+ m_bc.attemptImport(m_mined.blockData(), m_stateDB);
m_mineProgress.best = 0;
m_lock.unlock();
m_changed = true;
+ m_miningStarted = true; // need to re-commit to mine.
}
}
else
- usleep(100000);
+ this_thread::sleep_for(chrono::milliseconds(100));
+
+ m_changed = m_changed || changed;
}
void Client::lock()
diff --git a/libethereum/Client.h b/libethereum/Client.h
index e75369be9..1ef75c9f5 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -40,6 +40,18 @@ struct MineProgress
uint current;
};
+class Client;
+
+class ClientGuard
+{
+public:
+ inline ClientGuard(Client* _c);
+ inline ~ClientGuard();
+
+private:
+ Client* m_client;
+};
+
class Client
{
public:
@@ -50,16 +62,16 @@ public:
~Client();
/// Executes the given transaction.
- void transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data = u256s());
+ void transact(Secret _secret, Address _dest, u256 _amount, u256s _data = u256s());
/// Requires transactions involving this address be queued for inspection.
void setInterest(Address _dest);
/// @returns incoming minable transactions that we wanted to be notified of. Clears the queue.
- Transactions pendingQueue();
+ Transactions pendingQueue() { ClientGuard g(this); return m_tq.interestQueue(); }
/// @returns alterations in state of a mined block that we wanted to be notified of. Clears the queue.
- std::vector> minedQueue();
+ std::vector> minedQueue() { ClientGuard g(this); return m_bc.interestQueue(); }
// Not yet - probably best as using some sort of signals implementation.
/// Calls @a _f when a valid transaction is received that involves @a _dest and once per such transaction.
@@ -84,6 +96,8 @@ public:
/// Get the object representing the transaction queue.
TransactionQueue const& transactionQueue() const { return m_tq; }
+ void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
+
// Network stuff:
/// Get information on the current peer set.
@@ -97,6 +111,8 @@ public:
void connect(std::string const& _seedHost, short _port = 30303);
/// Stop the network subsystem.
void stopNetwork();
+ /// Get access to the peer server object. This will be null if the network isn't online.
+ PeerServer* peerServer() const { return m_net; }
// Mining stuff:
@@ -119,6 +135,7 @@ private:
TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain.
Overlay m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_s; ///< The present state of the client.
+ State m_mined; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
PeerServer* m_net = nullptr; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
#if defined(__APPLE__)
@@ -131,8 +148,19 @@ private:
enum { Active = 0, Deleting, Deleted } m_workState = Active;
bool m_doMine = false; ///< Are we supposed to be mining?
MineProgress m_mineProgress;
+ mutable bool m_miningStarted = false;
mutable bool m_changed;
};
+inline ClientGuard::ClientGuard(Client* _c): m_client(_c)
+{
+ m_client->lock();
+}
+
+inline ClientGuard::~ClientGuard()
+{
+ m_client->unlock();
+}
+
}
diff --git a/libethereum/Common.cpp b/libethereum/Common.cpp
index bede9f1fb..2041b25bd 100644
--- a/libethereum/Common.cpp
+++ b/libethereum/Common.cpp
@@ -43,8 +43,8 @@ int eth::g_logVerbosity = 8;
map eth::g_logOverride;
#if !defined(__APPLE__)
-thread_local std::string eth::t_logThreadName = "???";
-static std::string g_mainThreadName = (eth::t_logThreadName = "main");
+thread_local char const* eth::t_logThreadName = "???";
+static char const* g_mainThreadName = (eth::t_logThreadName = "main");
#endif
void eth::simpleDebugOut(std::string const& _s, char const*)
@@ -190,13 +190,50 @@ Address eth::toAddress(Secret _private)
KeyPair KeyPair::create()
{
+ secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution d(0, 255);
- KeyPair ret;
- for (uint i = 0; i < 32; ++i)
- ret.m_secret[i] = d(s_eng);
- ret.m_address = toAddress(ret.m_secret);
- return ret;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ h256 sec;
+ for (uint i = 0; i < 32; ++i)
+ sec[i] = d(s_eng);
+
+ KeyPair ret(sec);
+ if (ret.address())
+ return ret;
+ }
+ return KeyPair();
+}
+
+KeyPair::KeyPair(h256 _sec):
+ m_secret(_sec)
+{
+ int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
+ if (!ok)
+ return;
+
+ byte pubkey[65];
+ int pubkeylen = 65;
+ ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
+ if (!ok || pubkeylen != 65)
+ return;
+
+ ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
+ if (!ok)
+ return;
+
+ m_secret = m_secret;
+ memcpy(m_public.data(), &(pubkey[1]), 64);
+ m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
+
+#if ETH_ADDRESS_DEBUG
+ cout << "---- ADDRESS -------------------------------" << endl;
+ cout << "SEC: " << m_secret << endl;
+ cout << "PUB: " << m_public << endl;
+ cout << "ADR: " << m_address << endl;
+#endif
}
static const vector> g_units =
diff --git a/libethereum/Common.h b/libethereum/Common.h
index a184a0906..d066dc193 100644
--- a/libethereum/Common.h
+++ b/libethereum/Common.h
@@ -127,6 +127,7 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h)
return _out;
}
+using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector;
@@ -135,6 +136,7 @@ using h256Set = std::set;
using h160Set = std::set;
using Secret = h256;
+using Public = h512;
using Address = h160;
using Addresses = h160s;
@@ -158,8 +160,8 @@ public:
extern std::map g_logOverride;
#if !defined(__APPLE__)
-extern thread_local std::string t_logThreadName;
-inline void setThreadName(std::string const& _n) { t_logThreadName = _n; }
+extern thread_local char const* t_logThreadName;
+inline void setThreadName(char const* _n) { t_logThreadName = _n; }
#endif
struct LogChannel { static const char constexpr* name = " "; static const int verbosity = 1; };
@@ -167,7 +169,7 @@ struct LeftChannel: public LogChannel { static const char constexpr* name = "<<<
struct RightChannel: public LogChannel { static const char constexpr* name = ">>>"; };
struct WarnChannel: public LogChannel { static const char constexpr* name = "!!!"; static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char constexpr* name = "***"; };
-struct DebugChannel: public LogChannel { static const char constexpr* name = "---"; static const int verbosity = 0; };
+struct DebugChannel: public LogChannel { static const char constexpr* name = "---"; static const int verbosity = 7; };
extern int g_logVerbosity;
extern std::function g_logPost;
@@ -434,15 +436,19 @@ class KeyPair
{
public:
KeyPair() {}
- KeyPair(Secret _k): m_secret(_k), m_address(toAddress(_k)) {}
+ KeyPair(Secret _k);
static KeyPair create();
Secret const& secret() const { return m_secret; }
+ Secret const& sec() const { return m_secret; }
+ Public const& pub() const { return m_public; }
+
Address const& address() const { return m_address; }
private:
Secret m_secret;
+ Public m_public;
Address m_address;
};
diff --git a/libethereum/FileSystem.cpp b/libethereum/FileSystem.cpp
index c6a7aec1a..0633f3755 100644
--- a/libethereum/FileSystem.cpp
+++ b/libethereum/FileSystem.cpp
@@ -22,6 +22,7 @@
*/
#include "FileSystem.h"
+#include "Common.h"
#ifdef _WIN32
#include
diff --git a/libethereum/PeerNetwork.cpp b/libethereum/PeerNetwork.cpp
index ecc2e6f72..59f855798 100644
--- a/libethereum/PeerNetwork.cpp
+++ b/libethereum/PeerNetwork.cpp
@@ -30,6 +30,7 @@
#endif
#include
+#include
#include "Exceptions.h"
#include "Common.h"
#include "BlockChain.h"
@@ -42,6 +43,8 @@ using namespace eth;
#define clogS(X) eth::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
+static const int c_protocolVersion = 3;
+
static const eth::uint c_maxHashes = 256; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.
static const eth::uint c_maxBlocksAsk = 2048; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
@@ -94,21 +97,29 @@ bool PeerSession::interpret(RLP const& _r)
m_protocolVersion = _r[1].toInt();
m_networkId = _r[2].toInt();
auto clientVersion = _r[3].toString();
- m_caps = _r.itemCount() > 4 ? _r[4].toInt() : 0x07;
- m_listenPort = _r.itemCount() > 5 ? _r[5].toInt() : 0;
+ m_caps = _r[4].toInt();
+ m_listenPort = _r[5].toInt();
+ m_id = _r[6].toHash();
+
+ clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << asHex(m_id.ref().cropped(0, 4)) << showbase << hex << m_caps << dec << m_listenPort;
- clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << showbase << hex << m_caps << dec << m_listenPort;
+ if (m_server->m_peers.count(m_id) || !m_id)
+ {
+ // Already connected.
+ disconnect(DuplicatePeer);
+ }
+ m_server->m_peers[m_id] = shared_from_this();
- if (m_protocolVersion != 1 || m_networkId != m_reqNetworkId)
+ if (m_protocolVersion != c_protocolVersion || m_networkId != m_reqNetworkId)
{
- disconnect();
+ disconnect(IncompatibleProtocol);
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), (short)m_socket.remote_endpoint().port(), std::chrono::steady_clock::duration()}); }
catch (...)
{
- disconnect();
+ disconnect(BadProtocol);
return false;
}
@@ -131,13 +142,30 @@ bool PeerSession::interpret(RLP const& _r)
break;
}
case DisconnectPacket:
- clogS(NetMessageSummary) << "Disconnect";
+ {
+ string reason = "Unspecified";
+ if (_r.itemCount() > 1 && _r[1].isInt())
+ switch (_r[1].toInt())
+ {
+ case DisconnectRequested: reason = "Disconnect was requested."; break;
+ case TCPError: reason = "Low-level TCP communication error."; break;
+ case BadProtocol: reason = "Data format error."; break;
+ case UselessPeer: reason = "We had no use to peer."; break;
+ case TooManyPeers: reason = "Peer had too many connections."; break;
+ case DuplicatePeer: reason = "Peer was already connected."; break;
+ case WrongGenesis: reason = "Disagreement over genesis block."; break;
+ case IncompatibleProtocol: reason = "Peer protocol versions are incompatible."; break;
+ case ClientQuit: reason = "Peer is exiting."; break;
+ }
+
+ clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
+ }
case PingPacket:
{
// clogS(NetMessageSummary) << "Ping";
@@ -152,14 +180,14 @@ bool PeerSession::interpret(RLP const& _r)
case GetPeersPacket:
{
clogS(NetMessageSummary) << "GetPeers";
- std::vector peers = m_server->potentialPeers();
+ auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
for (auto i: peers)
{
- clogS(NetMessageDetail) << "Sending peer " << i;
- s.appendList(2) << i.address().to_v4().to_bytes() << i.port();
+ clogS(NetMessageDetail) << "Sending peer " << asHex(i.first.ref().cropped(0, 4)) << i.second;
+ s.appendList(3) << i.second.address().to_v4().to_bytes() << i.second.port() << i.first;
}
sealAndSend(s);
break;
@@ -169,7 +197,16 @@ bool PeerSession::interpret(RLP const& _r)
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto ep = bi::tcp::endpoint(bi::address_v4(_r[i][0].toArray()), _r[i][1].toInt());
- clogS(NetAllDetail) << "Checking: " << ep;
+ Public id;
+ if (_r[i].itemCount() > 2)
+ id = _r[i][2].toHash();
+
+ clogS(NetAllDetail) << "Checking: " << ep << "(" << asHex(id.ref().cropped(0, 4)) << ")";
+
+ // check that it's not us or one we already know:
+ if (id && (m_server->m_key.pub() == id || m_server->m_peers.count(id) || m_server->m_incomingPeers.count(id)))
+ goto CONTINUE;
+
// check that we're not already connected to addr:
if (!ep.port())
goto CONTINUE;
@@ -177,16 +214,16 @@ bool PeerSession::interpret(RLP const& _r)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
for (auto i: m_server->m_peers)
- if (shared_ptr p = i.lock())
+ if (shared_ptr p = i.second.lock())
{
clogS(NetAllDetail) << " ...against " << p->endpoint();
if (p->m_socket.is_open() && p->endpoint() == ep)
goto CONTINUE;
}
for (auto i: m_server->m_incomingPeers)
- if (i == ep)
+ if (i.second == ep)
goto CONTINUE;
- m_server->m_incomingPeers.push_back(ep);
+ m_server->m_incomingPeers.insert(make_pair(id, ep));
clogS(NetMessageDetail) << "New peer: " << ep;
CONTINUE:;
}
@@ -313,7 +350,7 @@ bool PeerSession::interpret(RLP const& _r)
if (noGood == m_server->m_chain->genesisHash())
{
clogS(NetWarn) << "Discordance over genesis block! Disconnect.";
- disconnect();
+ disconnect(WrongGenesis);
}
else
{
@@ -410,14 +447,14 @@ void PeerSession::dropped()
}catch (...){}
m_socket.close();
for (auto i = m_server->m_peers.begin(); i != m_server->m_peers.end(); ++i)
- if (i->lock().get() == this)
+ if (i->second.lock().get() == this)
{
m_server->m_peers.erase(i);
break;
}
}
-void PeerSession::disconnect()
+void PeerSession::disconnect(int _reason)
{
if (m_socket.is_open())
{
@@ -425,7 +462,7 @@ void PeerSession::disconnect()
{
RLPStream s;
prep(s);
- s.appendList(1) << DisconnectPacket;
+ s.appendList(1) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
@@ -446,9 +483,7 @@ void PeerSession::start()
{
RLPStream s;
prep(s);
- s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)1 << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0);
- if (m_server->m_public.port())
- s << m_server->m_public.port();
+ s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)c_protocolVersion << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
@@ -516,31 +551,34 @@ PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch,
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService),
+ m_key(KeyPair::create()),
m_requiredNetworkId(_networkId)
{
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
- clog(NetNote) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
+ clog(NetNote) << "Id:" << asHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
}
-PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId):
+PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m):
m_clientVersion(_clientVersion),
+ m_mode(_m),
m_listenPort(-1),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
+ m_key(KeyPair::create()),
m_requiredNetworkId(_networkId)
{
// populate addresses.
populateAddresses();
- clog(NetNote) << "Genesis: " << m_chain->genesisHash();
+ clog(NetNote) << "Id:" << asHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::~PeerServer()
{
for (auto const& i: m_peers)
- if (auto p = i.lock())
- p->disconnect();
+ if (auto p = i.second.lock())
+ p->disconnect(ClientQuit);
delete m_upnp;
}
@@ -654,17 +692,17 @@ void PeerServer::populateAddresses()
#endif
}
-std::vector PeerServer::potentialPeers()
+std::map PeerServer::potentialPeers()
{
- std::vector ret;
+ std::map ret;
if (!m_public.address().is_unspecified())
- ret.push_back(m_public);
+ ret.insert(make_pair(m_key.pub(), m_public));
for (auto i: m_peers)
- if (auto j = i.lock())
+ if (auto j = i.second.lock())
{
auto ep = j->endpoint();
- if (ep.port())
- ret.push_back(ep);
+ if (ep.port() && j->m_id)
+ ret.insert(make_pair(i.first, ep));
}
return ret;
}
@@ -684,7 +722,6 @@ void PeerServer::ensureAccepting()
clog(NetNote) << "Accepted connection from " << m_socket.remote_endpoint();
} catch (...){}
auto p = std::make_shared(this, std::move(m_socket), m_requiredNetworkId);
- m_peers.push_back(p);
p->start();
}
catch (std::exception const& _e)
@@ -712,7 +749,6 @@ void PeerServer::connect(bi::tcp::endpoint const& _ep)
else
{
auto p = make_shared(this, std::move(*s), m_requiredNetworkId);
- m_peers.push_back(p);
clog(NetNote) << "Connected to " << p->endpoint();
p->start();
}
@@ -733,7 +769,7 @@ bool PeerServer::process(BlockChain& _bc)
if (fullProcess)
for (auto i = m_peers.begin(); i != m_peers.end();)
{
- auto p = i->lock();
+ auto p = i->second.lock();
if (p && p->m_socket.is_open() &&
(p->m_disconnect == chrono::steady_clock::time_point::max() || chrono::steady_clock::now() - p->m_disconnect < chrono::seconds(1))) // kill old peers that should be disconnected.
++i;
@@ -782,7 +818,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
if (fullProcess)
{
for (auto j: m_peers)
- if (auto p = j.lock())
+ if (auto p = j.second.lock())
{
bytes b;
uint n = 0;
@@ -798,7 +834,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
- ts.appendRaw(b).swapOut(b);
+ ts.appendRaw(b, n).swapOut(b);
seal(b);
p->send(&b);
}
@@ -818,7 +854,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b);
seal(b);
for (auto j: m_peers)
- if (auto p = j.lock())
+ if (auto p = j.second.lock())
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b);
@@ -867,7 +903,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
(PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
- if (auto p = i.lock())
+ if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
@@ -879,8 +915,8 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
break;
}
- connect(m_incomingPeers.back());
- m_incomingPeers.pop_back();
+ connect(m_incomingPeers.begin()->second);
+ m_incomingPeers.erase(m_incomingPeers.begin());
}
}
}
@@ -900,7 +936,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
shared_ptr worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
- if (auto p = i.lock())
+ if (auto p = i.second.lock())
if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
@@ -909,7 +945,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
- worst->disconnect();
+ worst->disconnect(TooManyPeers);
}
}
@@ -919,10 +955,10 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
std::vector PeerServer::peers() const
{
const_cast(this)->pingAll();
- usleep(200000);
+ this_thread::sleep_for(chrono::milliseconds(200));
std::vector ret;
for (auto& i: m_peers)
- if (auto j = i.lock())
+ if (auto j = i.second.lock())
if (j->m_socket.is_open())
ret.push_back(j->m_info);
return ret;
@@ -931,6 +967,6 @@ std::vector PeerServer::peers() const
void PeerServer::pingAll()
{
for (auto& i: m_peers)
- if (auto j = i.lock())
+ if (auto j = i.second.lock())
j->ping();
}
diff --git a/libethereum/PeerNetwork.h b/libethereum/PeerNetwork.h
index 66d05e02a..f8a28335a 100644
--- a/libethereum/PeerNetwork.h
+++ b/libethereum/PeerNetwork.h
@@ -21,6 +21,7 @@
#pragma once
+#include