diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 97545b36d..331155559 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -277,7 +277,7 @@
- 349
+ 408
251
@@ -298,26 +298,6 @@
4
- -
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
- Send
-
-
-
- -
-
-
-
@@ -325,6 +305,9 @@
+ -
+
+
-
@@ -338,6 +321,16 @@
+ -
+
+
+ Data
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
-
@@ -351,44 +344,45 @@
- -
-
-
-
-
-
-
-
-
- 430000000
-
-
- 100
+
-
+
+
+ -
+
+
+ Send
- -
-
-
- -
-
-
- Fee
+
-
+
+
+
+ 1
+ 0
+
+
+
+ (Create Contract)
- -
-
+
-
+
- Data
+
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
+
-
+
+
+
+
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 98e8e22b5..351f4b77f 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -24,8 +24,6 @@ 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" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM));
@@ -51,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);
@@ -137,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()) );
}
@@ -153,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()) );
}
@@ -189,6 +186,51 @@ 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());
@@ -233,9 +275,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)
@@ -243,12 +283,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 cafbb5652..016e00274 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -32,6 +32,10 @@ private slots:
void on_verbosity_sliderMoved();
void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked();
+ void on_destination_textChanged();
+ void on_data_textChanged();
+ void on_value_valueChanged() { updateFee(); }
+ void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_log_doubleClicked();
void on_about_triggered();
void on_quit_triggered() { close(); }
@@ -39,9 +43,14 @@ private slots:
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;
@@ -50,6 +59,7 @@ private:
QTimer* m_refresh;
QStringList m_servers;
QVector m_myKeys;
+ QStringList m_data;
QNetworkAccessManager m_webCtrl;
};
diff --git a/eth/main.cpp b/eth/main.cpp
index a6f55acc8..2bd7f865a 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -207,20 +207,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")
{
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index cd7f53de6..b053fa9c1 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -32,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);
@@ -95,6 +96,7 @@ void Client::stopNetwork()
void Client::startMining()
{
m_doMine = true;
+ m_miningStarted = true;
}
void Client::stopMining()
@@ -102,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());
@@ -120,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.
@@ -135,16 +138,23 @@ void Client::work()
// all blocks.
// Resynchronise state with block chain & trans
if (m_s.sync(m_bc))
- m_changed = true;
+ changed = true;
if (m_s.sync(m_tq))
- m_changed = true;
+ changed = true;
m_lock.unlock();
if (m_doMine)
{
+ if (changed || m_miningStarted)
+ {
+ m_mined = m_s;
+ 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;
@@ -153,7 +163,7 @@ 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;
@@ -161,6 +171,8 @@ void Client::work()
}
else
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 be485e768..70b94d84b 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -62,7 +62,7 @@ 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);
@@ -131,6 +131,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__)
@@ -143,6 +144,7 @@ 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;
};
diff --git a/libethereum/Common.cpp b/libethereum/Common.cpp
index f5896db95..2041b25bd 100644
--- a/libethereum/Common.cpp
+++ b/libethereum/Common.cpp
@@ -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 cd4f81af6..9f13dda29 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;
@@ -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/PeerNetwork.cpp b/libethereum/PeerNetwork.cpp
index f12ec4cae..7aa3480c1 100644
--- a/libethereum/PeerNetwork.cpp
+++ b/libethereum/PeerNetwork.cpp
@@ -95,21 +95,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 << "]" << showbase << hex << m_caps << dec << m_listenPort;
+ clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << asHex(m_id.ref().cropped(0, 4)) << showbase << hex << m_caps << dec << m_listenPort;
- if (m_protocolVersion != 1 || m_networkId != m_reqNetworkId)
+ if (m_server->m_peers.count(m_id) || !m_id)
{
- disconnect();
+ // Already connected.
+ disconnect(DuplicatePeer);
+ }
+ m_server->m_peers[m_id] = shared_from_this();
+
+ if (m_protocolVersion != 2 || m_networkId != m_reqNetworkId)
+ {
+ 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;
}
@@ -132,13 +140,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";
@@ -153,14 +178,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;
@@ -170,7 +195,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;
@@ -178,16 +212,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:;
}
@@ -314,7 +348,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
{
@@ -366,7 +400,6 @@ void PeerServer::seal(bytes& _b)
_b[5] = (len >> 16) & 0xff;
_b[6] = (len >> 8) & 0xff;
_b[7] = len & 0xff;
- cerr << "Sealed " << _b.size() << ": " << asHex(_b) << endl;
}
void PeerSession::sealAndSend(RLPStream& _s)
@@ -412,14 +445,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())
{
@@ -427,7 +460,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();
}
@@ -448,9 +481,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)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) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
@@ -518,31 +549,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;
}
@@ -656,17 +690,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;
}
@@ -686,7 +720,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)
@@ -714,7 +747,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();
}
@@ -735,7 +767,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;
@@ -784,7 +816,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;
@@ -820,7 +852,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);
@@ -869,7 +901,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();
@@ -881,8 +913,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());
}
}
}
@@ -902,7 +934,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;
@@ -911,7 +943,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
- worst->disconnect();
+ worst->disconnect(TooManyPeers);
}
}
@@ -924,7 +956,7 @@ std::vector PeerServer::peers() const
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;
@@ -933,6 +965,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