Browse Source

* Kill peers when too many

- Respect idealPeerCount.
  - Peer network traversal for peer discovery.
  - Check peer utility (useful transactions & blocks passed) for when
dismissing.
  - Respect peer count & dismiss/collect/stop listening for peers as
necessary.
cl-refactor
Gav Wood 11 years ago
parent
commit
f8a87c897d
  1. 7
      TODO
  2. 52
      libethereum/PeerNetwork.cpp
  3. 13
      libethereum/PeerNetwork.h

7
TODO

@ -23,11 +23,8 @@ FOR ALPHA:
Network:
* Manage GetBlocks properly; should work for when > 256 blocks away.
- configurable (lower) mine times, configurable (reduced) max blocks to be sent then check.
* Kill peers when too many
- Respect idealPeerCount.
- Peer network traversal for peer discovery.
- Check peer utility (useful transactions & blocks passed) for when dismissing.
- Respect peer count & dismiss/collect/stop listening for peers as necessary.
* Respect and handle capabilities.
* Use GetTransactions on connect & respect it.
UI:
* State panel shouldn't show pending (i.e. post-mined) transactions.

52
libethereum/PeerNetwork.cpp

@ -22,6 +22,7 @@
#include <sys/types.h>
#include <ifaddrs.h>
#include <chrono>
#include "Common.h"
#include "BlockChain.h"
#include "TransactionQueue.h"
@ -35,11 +36,13 @@ PeerSession::PeerSession(PeerServer* _s, bi::tcp::socket _socket, uint _rNId):
m_reqNetworkId(_rNId),
m_rating(0)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
}
PeerSession::~PeerSession()
{
disconnect();
m_socket.close();
}
bi::tcp::endpoint PeerSession::endpoint() const
@ -139,6 +142,8 @@ bool PeerSession::interpret(RLP const& _r)
}
break;
case Transactions:
if (m_server->m_mode == NodeMode::PeerServer)
break;
cout << std::setw(2) << m_socket.native_handle() << " | Transactions (" << dec << (_r.itemCount() - 1) << " entries)" << endl;
m_rating += _r.itemCount() - 1;
for (unsigned i = 1; i < _r.itemCount(); ++i)
@ -148,6 +153,8 @@ bool PeerSession::interpret(RLP const& _r)
}
break;
case Blocks:
if (m_server->m_mode == NodeMode::PeerServer)
break;
cout << std::setw(2) << m_socket.native_handle() << " | Blocks (" << dec << (_r.itemCount() - 1) << " entries)" << endl;
m_rating += _r.itemCount() - 1;
for (unsigned i = 1; i < _r.itemCount(); ++i)
@ -167,6 +174,8 @@ bool PeerSession::interpret(RLP const& _r)
break;
case GetChain:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
// ********************************************************************
// NEEDS FULL REWRITE!
h256s parents;
@ -239,6 +248,8 @@ bool PeerSession::interpret(RLP const& _r)
}
case NotInChain:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
h256 noGood = _r[1].toHash<h256>();
cout << std::setw(2) << m_socket.native_handle() << " | NotInChain (" << noGood << ")" << endl;
if (noGood != m_server->m_chain->genesisHash())
@ -337,12 +348,19 @@ void PeerSession::dropped()
void PeerSession::disconnect()
{
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s);
s.appendList(1) << (uint)Disconnect;
sealAndSend(s);
sleep(1);
m_disconnect = chrono::steady_clock::now();
}
else
m_socket.close();
}
}
void PeerSession::start()
@ -538,18 +556,16 @@ bool PeerServer::process(BlockChain& _bc)
bool ret = false;
m_ioService.poll();
for (auto i = m_peers.begin(); i != m_peers.end();)
if (auto j = i->lock())
if (j->m_socket.is_open())
{
auto p = i->lock();
if (p && p->m_socket.is_open() &&
(p->m_disconnect == chrono::steady_clock::time_point::max() || chrono::steady_clock::now() - p->m_disconnect < chrono::seconds(1))) // kill old peers that should be disconnected.
++i;
else
{
i = m_peers.erase(i);
ret = true;
}
else
{
i = m_peers.erase(i);
ret = true;
}
return ret;
}
@ -658,7 +674,6 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
// guarantees that everyone else respect the rules of the system. (i.e. obeys laws).
// Connect to additional peers
// TODO: Need to avoid connecting to self & existing peers. Existing peers is easy, but need portable method of listing all addresses we can listen to avoid self.
while (m_peers.size() < m_idealPeerCount)
{
if (m_incomingPeers.empty())
@ -679,6 +694,25 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
connect(m_incomingPeers.back());
m_incomingPeers.pop_back();
}
while (m_peers.size() > m_idealPeerCount)
{
// look for worst peer to kick off
// first work out how many are old enough to kick off.
shared_ptr<PeerSession> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.lock())
if (chrono::steady_clock::now() - p->m_connect > chrono::seconds(10))
{
++agedPeers;
if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // keep younger ones.
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
worst->dropped(); // should really disconnect, but that's no good.
}
return ret;
}

13
libethereum/PeerNetwork.h

@ -100,6 +100,8 @@ private:
short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
unsigned m_rating;
@ -107,6 +109,12 @@ private:
std::set<h256> m_knownTransactions;
};
enum class NodeMode
{
Full,
PeerServer
};
class PeerServer
{
friend class PeerSession;
@ -129,7 +137,9 @@ public:
bool process(BlockChain& _bc);
/// Set ideal number of peers.
void setIdealPeerCount(uint _n) { m_idealPeerCount = _n; }
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
void setMode(NodeMode _m) { m_mode = _m; }
/// Get peer information.
std::vector<PeerInfo> peers() const;
@ -149,6 +159,7 @@ private:
std::vector<bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;

Loading…
Cancel
Save