Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into build_enhancement

cl-refactor
sveneh 10 years ago
parent
commit
1cbb432e2c
  1. 34
      alethzero/Main.ui
  2. 27
      alethzero/MainWin.cpp
  3. 93
      eth/main.cpp
  4. 2
      libdevcore/Common.cpp
  5. 2
      libdevcrypto/MemoryDB.h
  6. 2
      libdevcrypto/TrieDB.h
  7. 4
      libethcore/CommonEth.cpp
  8. 37
      libethereum/Client.cpp
  9. 10
      libethereum/EthereumHost.cpp
  10. 9
      libethereum/State.cpp
  11. 112
      libevm/VM.h
  12. 8
      libp2p/Capability.cpp
  13. 2
      libp2p/Capability.h
  14. 5
      libp2p/Common.cpp
  15. 20
      libp2p/Common.h
  16. 131
      libp2p/Host.cpp
  17. 33
      libp2p/Host.h
  18. 245
      libp2p/Session.cpp
  19. 57
      libp2p/Session.h
  20. 2
      libqethereum/QEthereum.cpp
  21. 5
      libwebthree/WebThree.h

34
alethzero/Main.ui

@ -1480,6 +1480,40 @@ font-size: 14pt</string>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_13">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Nodes</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_13">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="nodes">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>

27
alethzero/MainWin.cpp

@ -751,10 +751,35 @@ void Main::refreshNetwork()
{
auto ps = web3()->peers();
map<h512, QString> clients;
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear();
for (PeerInfo const& i: ps)
ui->peers->addItem(QString("[%7] %3 ms - %1:%2 - %4 %5 %6").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()).arg(i.clientVersion.c_str()).arg(QString::fromStdString(toString(i.caps))).arg(QString::fromStdString(toString(i.notes))).arg(i.socket));
ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6")
.arg(QString::fromStdString(i.host))
.arg(i.port)
.arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count())
.arg(clients[i.id] = QString::fromStdString(i.clientVersion))
.arg(QString::fromStdString(toString(i.caps)))
.arg(QString::fromStdString(toString(i.notes)))
.arg(i.socket)
.arg(QString::fromStdString(i.id.abridged())));
auto ns = web3()->nodes();
ui->nodes->clear();
for (p2p::Node const& i: ns)
if (!i.dead)
ui->nodes->addItem(QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8")
.arg(QString::fromStdString(i.id.abridged()))
.arg(QString::fromStdString(toString(i.address)))
.arg(i.id == web3()->id() ? "self" : i.isOffline() ? i.secondsSinceLastAttempted() > -1 ? "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : "session-fail" : clients[i.id])
.arg(i.secondsSinceLastAttempted())
.arg(i.secondsSinceLastConnected())
.arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "")
.arg(i.rating)
.arg((int)i.idOrigin)
);
}
void Main::refreshAll()

93
eth/main.cpp

@ -24,6 +24,7 @@
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#if ETH_JSONRPC
@ -166,6 +167,13 @@ string pretty(h160 _a, dev::eth::State _st)
return ns;
}
bool g_exit = false;
void sighandler(int)
{
g_exit = true;
}
int main(int argc, char** argv)
{
unsigned short listenPort = 30303;
@ -316,6 +324,9 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
auto nodesState = contents(dbPath + "/nodeState.rlp");
web3.restoreNodes(&nodesState);
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
web3.startNetwork();
@ -334,11 +345,15 @@ int main(int argc, char** argv)
}
#endif
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
if (interactive)
{
string logbuf;
string l;
while (true)
while (!g_exit)
{
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; };
cout << logbuf << "Press Enter" << flush;
@ -615,46 +630,47 @@ int main(int argc, char** argv)
try
{
e.setup(&r);
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << endl << " STACK" << endl;
for (auto i: vm->stack())
f << (h256)i << endl;
f << " MEMORY" << endl << dev::memDump(vm->memory());
f << " STORAGE" << endl;
for (auto const& i: ext->state().storage(ext->myAddress))
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
else if (format == "standard+")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress))
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
e.go(oof);
e.finalize(oof);
}
catch(Exception const& _e)
{
// TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain.
cwarn << diagnostic_information(_e);
}
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << endl << " STACK" << endl;
for (auto i: vm->stack())
f << (h256)i << endl;
f << " MEMORY" << endl << dev::memDump(vm->memory());
f << " STORAGE" << endl;
for (auto const& i: ext->state().storage(ext->myAddress))
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
else if (format == "standard+")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress))
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
e.go(oof);
e.finalize(oof);
}
}
else if (c && cmd == "inspect")
@ -764,7 +780,7 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number;
if (mining)
c->startMining();
while (true)
while (!g_exit)
{
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
@ -772,9 +788,10 @@ int main(int argc, char** argv)
}
}
else
while (true)
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
writeFile(dbPath + "/nodeState.rlp", web3.saveNodes());
return 0;
}

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.7.2";
char const* Version = "0.7.3";
}

2
libdevcrypto/MemoryDB.h

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 12; };
struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; };
#define dbdebug clog(DBChannel)

2
libdevcrypto/TrieDB.h

@ -42,7 +42,7 @@ namespace dev
namespace eth
{
struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 6; };
struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; };
#define tdebug clog(TrieDBChannel)
struct InvalidTrie: virtual dev::Exception {};

4
libethcore/CommonEth.cpp

@ -34,8 +34,8 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 34;
const unsigned c_databaseVersion = 2;
const unsigned c_protocolVersion = 35;
const unsigned c_databaseVersion = 3;
static const vector<pair<u256, string>> g_units =
{

37
libethereum/Client.cpp

@ -323,23 +323,30 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
State temp;
Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
bytes out;
try
{
ReadGuard l(x_stateDB);
temp = m_postMine;
t.nonce = temp.transactionsFrom(toAddress(_secret));
State temp;
Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
temp = m_postMine;
t.nonce = temp.transactionsFrom(toAddress(_secret));
}
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = _dest;
t.data = _data;
t.sign(_secret);
u256 gasUsed = temp.execute(t.data, &out, false);
(void)gasUsed; // TODO: do something with gasused which it returns.
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = _dest;
t.data = _data;
t.sign(_secret);
bytes out;
u256 gasUsed = temp.execute(t.data, &out, false);
(void)gasUsed; // TODO: do something with gasused which it returns.
return out;
}

10
libethereum/EthereumHost.cpp

@ -189,20 +189,14 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
// If we've finished our initial sync send any new blocks.
if (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
// TODO: clean up
h256s hs;
hs.push_back(_currentHash);
bytes bs;
for (auto h: hs)
bs += m_chain.block(h);
clog(NetMessageSummary) << "Sending" << hs.size() << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
for (auto j: peers())
{
auto p = j->cap<EthereumPeer>();
RLPStream ts;
p->prep(ts, NewBlockPacket, hs.size()).appendRaw(bs, hs.size());
p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty);
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))

9
libethereum/State.cpp

@ -1054,14 +1054,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
Manifest ms;
Executive e(*this, &ms);
try
{
e.setup(_rlp);
}
catch (Exception const & _e)
{
cwarn << diagnostic_information(_e);
}
e.setup(_rlp);
u256 startGasUsed = gasUsed();

112
libevm/VM.h

@ -188,8 +188,116 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
}
default:
case Instruction::ADD:
case Instruction::MUL:
case Instruction::SUB:
case Instruction::DIV:
case Instruction::SDIV:
case Instruction::MOD:
case Instruction::SMOD:
case Instruction::EXP:
case Instruction::NEG:
case Instruction::LT:
case Instruction::GT:
case Instruction::SLT:
case Instruction::SGT:
case Instruction::EQ:
case Instruction::NOT:
case Instruction::AND:
case Instruction::OR:
case Instruction::XOR:
case Instruction::BYTE:
case Instruction::ADDMOD:
case Instruction::MULMOD:
case Instruction::ADDRESS:
case Instruction::ORIGIN:
case Instruction::CALLER:
case Instruction::CALLVALUE:
case Instruction::CALLDATALOAD:
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::EXTCODESIZE:
case Instruction::GASPRICE:
case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
case Instruction::DIFFICULTY:
case Instruction::GASLIMIT:
case Instruction::PUSH1:
case Instruction::PUSH2:
case Instruction::PUSH3:
case Instruction::PUSH4:
case Instruction::PUSH5:
case Instruction::PUSH6:
case Instruction::PUSH7:
case Instruction::PUSH8:
case Instruction::PUSH9:
case Instruction::PUSH10:
case Instruction::PUSH11:
case Instruction::PUSH12:
case Instruction::PUSH13:
case Instruction::PUSH14:
case Instruction::PUSH15:
case Instruction::PUSH16:
case Instruction::PUSH17:
case Instruction::PUSH18:
case Instruction::PUSH19:
case Instruction::PUSH20:
case Instruction::PUSH21:
case Instruction::PUSH22:
case Instruction::PUSH23:
case Instruction::PUSH24:
case Instruction::PUSH25:
case Instruction::PUSH26:
case Instruction::PUSH27:
case Instruction::PUSH28:
case Instruction::PUSH29:
case Instruction::PUSH30:
case Instruction::PUSH31:
case Instruction::PUSH32:
case Instruction::POP:
case Instruction::DUP1:
case Instruction::DUP2:
case Instruction::DUP3:
case Instruction::DUP4:
case Instruction::DUP5:
case Instruction::DUP6:
case Instruction::DUP7:
case Instruction::DUP8:
case Instruction::DUP9:
case Instruction::DUP10:
case Instruction::DUP11:
case Instruction::DUP12:
case Instruction::DUP13:
case Instruction::DUP14:
case Instruction::DUP15:
case Instruction::DUP16:
case Instruction::SWAP1:
case Instruction::SWAP2:
case Instruction::SWAP3:
case Instruction::SWAP4:
case Instruction::SWAP5:
case Instruction::SWAP6:
case Instruction::SWAP7:
case Instruction::SWAP8:
case Instruction::SWAP9:
case Instruction::SWAP10:
case Instruction::SWAP11:
case Instruction::SWAP12:
case Instruction::SWAP13:
case Instruction::SWAP14:
case Instruction::SWAP15:
case Instruction::SWAP16:
case Instruction::JUMP:
case Instruction::JUMPI:
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
case Instruction::JUMPDEST:
break;
default:
BOOST_THROW_EXCEPTION(BadInstruction());
}
newTempSize = (newTempSize + 31) / 32 * 32;
@ -669,8 +777,6 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
}
case Instruction::STOP:
return bytesConstRef();
default:
BOOST_THROW_EXCEPTION(BadInstruction());
}
}
if (_steps == (uint64_t)-1)

8
libp2p/Capability.cpp

@ -53,14 +53,14 @@ void Capability::sealAndSend(RLPStream& _s)
m_session->sealAndSend(_s);
}
void Capability::sendDestroy(bytes& _msg)
void Capability::send(bytesConstRef _msg)
{
m_session->sendDestroy(_msg);
m_session->send(_msg);
}
void Capability::send(bytesConstRef _msg)
void Capability::send(bytes&& _msg)
{
m_session->send(_msg);
m_session->send(move(_msg));
}
void Capability::addRating(unsigned _r)

2
libp2p/Capability.h

@ -52,7 +52,7 @@ protected:
RLPStream& prep(RLPStream& _s, unsigned _id, unsigned _args = 0);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytes&& _msg);
void send(bytesConstRef _msg);
void addRating(unsigned _r);

5
libp2p/Common.cpp

@ -64,7 +64,12 @@ std::string p2p::reasonOf(DisconnectReason _r)
case TooManyPeers: return "Peer had too many connections.";
case DuplicatePeer: return "Peer was already connected.";
case IncompatibleProtocol: return "Peer protocol versions are incompatible.";
case NullIdentity: return "Null identity given.";
case ClientQuit: return "Peer is exiting.";
case UnexpectedIdentity: return "Unexpected identity given.";
case LocalIdentity: return "Connected to ourselves.";
case UserReason: return "Subprotocol reason.";
case NoDisconnect: return "(No disconnect has happened.)";
default: return "Unknown reason.";
}
}

20
libp2p/Common.h

@ -87,9 +87,27 @@ enum DisconnectReason
NullIdentity,
ClientQuit,
UnexpectedIdentity,
UserReason = 0x10
LocalIdentity,
PingTimeout,
UserReason = 0x10,
NoDisconnect = 0xffff
};
inline bool isPermanentProblem(DisconnectReason _r)
{
switch (_r)
{
case DuplicatePeer:
case IncompatibleProtocol:
case NullIdentity:
case UnexpectedIdentity:
case LocalIdentity:
return true;
default:
return false;
}
}
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);

131
libp2p/Host.cpp

@ -66,7 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_key(KeyPair::create())
{
populateAddresses();
m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << id().abridged();
if (_start)
start();
@ -112,7 +111,6 @@ void Host::start()
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << id().abridged();
for (auto const& h: m_capabilities)
@ -144,7 +142,7 @@ void Host::stop()
unsigned Host::protocolVersion() const
{
return 1;
return 2;
}
void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
@ -345,31 +343,47 @@ void Host::populateAddresses()
#endif
}
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId)
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{
RecursiveGuard l(x_peers);
if (_a.port() < 30300 && _a.port() > 30303)
cwarn << "Wierd port being recorded!";
if (_a.port() >= 49152)
{
cwarn << "Private port being recorded - setting to 0";
_a = bi::tcp::endpoint(_a.address(), 0);
}
cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]");
// First check for another node with the same connection credentials, and put it in oldId if found.
if (!_oldId)
for (pair<h512, shared_ptr<Node>> const& n: m_nodes)
if (n.second->address == _a && n.second->id != _id)
{
_oldId = n.second->id;
break;
}
unsigned i;
if (!m_nodes.count(_id))
{
shared_ptr<Node> old;
if (m_nodes.count(_oldId))
{
old = m_nodes[_oldId];
i = old->index;
i = m_nodes[_oldId]->index;
m_nodes.erase(_oldId);
m_nodesList[i] = _id;
m_nodes[id()] = make_shared<Node>();
}
else
{
i = m_nodesList.size();
m_nodesList.push_back(_id);
m_nodes[_id] = make_shared<Node>();
}
m_nodes[_id]->address = m_public;
m_nodes[_id]->index = i;
m_nodes[_id] = make_shared<Node>();
m_nodes[_id]->id = _id;
m_nodes[_id]->address = _a;
m_nodes[_id]->index = i;
m_nodes[_id]->idOrigin = _o;
}
else
@ -390,6 +404,8 @@ shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin
cnote << m_nodes[_id]->index << ":" << m_ready;
m_hadNewNodes = true;
return m_nodes[_id];
}
@ -398,7 +414,8 @@ Nodes Host::potentialPeers(RangeMask<unsigned> const& _known)
RecursiveGuard l(x_peers);
Nodes ret;
for (auto i: m_ready - (m_private + _known))
auto ns = (m_netPrefs.localNetworking ? _known : (m_private + _known)).inverted();
for (auto i: ns)
ret.push_back(*m_nodes[m_nodesList[i]]);
return ret;
}
@ -494,7 +511,9 @@ void Host::connect(bi::tcp::endpoint const& _ep)
void Node::connect(Host* _h)
{
clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address;
clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged();
lastAttempted = std::chrono::system_clock::now();
failedAttempts++;
_h->m_ready -= index;
bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService);
s->async_connect(address, [=](boost::system::error_code const& ec)
@ -502,14 +521,13 @@ void Node::connect(Host* _h)
if (ec)
{
clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")";
failedAttempts++;
lastDisconnect = TCPError;
lastAttempted = std::chrono::system_clock::now();
_h->m_ready += index;
}
else
{
clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
failedAttempts = 0;
lastConnected = std::chrono::system_clock::now();
auto p = make_shared<Session>(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
p->start();
@ -532,14 +550,31 @@ bool Host::havePeer(NodeId _id) const
return !!m_peers.count(_id);
}
unsigned cumulativeFallback(unsigned _failed)
unsigned Node::fallbackSeconds() const
{
if (_failed < 5)
return _failed * 5;
else if (_failed < 15)
return 25 + (_failed - 5) * 10;
else
return 25 + 100 + (_failed - 15) * 20;
switch (lastDisconnect)
{
case BadProtocol:
return 30 * (failedAttempts + 1);
case UselessPeer:
case TooManyPeers:
case ClientQuit:
return 15 * (failedAttempts + 1);
case NoDisconnect:
return 0;
default:
if (failedAttempts < 5)
return failedAttempts * 5;
else if (failedAttempts < 15)
return 25 + (failedAttempts - 5) * 10;
else
return 25 + 100 + (failedAttempts - 15) * 20;
}
}
bool Node::shouldReconnect() const
{
return chrono::system_clock::now() > lastAttempted + chrono::seconds(fallbackSeconds());
}
void Host::growPeers()
@ -553,7 +588,7 @@ void Host::growPeers()
toTry -= m_private;
set<Node> ns;
for (auto i: toTry)
if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts)))
if (m_nodes[m_nodesList[i]]->shouldReconnect())
ns.insert(*m_nodes[m_nodesList[i]]);
if (ns.size())
@ -566,25 +601,13 @@ void Host::growPeers()
else
{
ensureAccepting();
if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
requestPeers();
for (auto const& i: m_peers)
if (auto p = i.second.lock())
p->ensureNodesRequested();
}
}
}
void Host::requestPeers()
{
RLPStream s;
bytes b;
Session::prep(s, GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
}
void Host::prunePeers()
{
RecursiveGuard l(x_peers);
@ -637,6 +660,25 @@ void Host::doWork()
{
growPeers();
prunePeers();
if (m_hadNewNodes)
{
for (auto p: m_peers)
if (auto pp = p.second.lock())
pp->serviceNodesRequest();
m_hadNewNodes = false;
}
if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s.
{
for (auto p: m_peers)
if (auto pp = p.second.lock())
if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
pp->disconnect(PingTimeout);
pingAll();
}
m_ioService.poll();
}
@ -646,6 +688,7 @@ void Host::pingAll()
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
m_lastPing = chrono::steady_clock::now();
}
bytes Host::saveNodes() const
@ -657,7 +700,8 @@ bytes Host::saveNodes() const
for (auto const& i: m_nodes)
{
Node const& n = *(i.second);
if (n.id != id() && !isPrivateAddress(n.address.address()))
// TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address()))
{
nodes.appendList(10);
if (n.address.address().is_v4())
@ -667,7 +711,7 @@ bytes Host::saveNodes() const
nodes << n.address.port() << n.id << (int)n.idOrigin
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastConnected.time_since_epoch()).count()
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastAttempted.time_since_epoch()).count()
<< n.failedAttempts << n.lastDisconnect << n.score << n.rating;
<< n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
count++;
}
}
@ -686,7 +730,11 @@ void Host::restoreNodes(bytesConstRef _b)
switch (r[0].toInt<int>())
{
case 0:
{
auto oldId = id();
m_key = KeyPair(r[1].toHash<Secret>());
noteNode(id(), m_public, Origin::Perfect, false, oldId);
for (auto i: r[2])
{
bi::tcp::endpoint ep;
@ -702,11 +750,12 @@ void Host::restoreNodes(bytesConstRef _b)
n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
n->failedAttempts = i[6].toInt<unsigned>();
n->lastDisconnect = (int)i[7].toInt<unsigned>();
n->lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
n->score = (int)i[8].toInt<unsigned>();
n->rating = (int)i[9].toInt<unsigned>();
}
}
}
default:;
}
else

33
libp2p/Host.h

@ -64,19 +64,26 @@ struct Node
bi::tcp::endpoint address; ///< As reported from the node itself.
int score = 0; ///< All time cumulative.
int rating = 0; ///< Trending.
bool dead = false; ///< If true, we believe this node is permanently dead - forget all about it.
std::chrono::system_clock::time_point lastConnected;
std::chrono::system_clock::time_point lastAttempted;
unsigned failedAttempts = 0;
int lastDisconnect = -1; ///< Reason for disconnect that happened last.
DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
Origin idOrigin = Origin::Unknown; ///< Thirdparty
Origin idOrigin = Origin::Unknown; ///< How did we get to know this node's id?
bool offline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; }
int secondsSinceLastConnected() const { return lastConnected == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - lastConnected).count(); }
int secondsSinceLastAttempted() const { return lastAttempted == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - lastAttempted).count(); }
unsigned fallbackSeconds() const;
bool shouldReconnect() const;
bool isOffline() const { return lastAttempted > lastConnected; }
bool operator<(Node const& _n) const
{
if (offline() != _n.offline())
return offline();
else if (offline())
if (isOffline() != _n.isOffline())
return isOffline();
else if (isOffline())
if (lastAttempted == _n.lastAttempted)
return failedAttempts < _n.failedAttempts;
else
@ -114,7 +121,7 @@ class Host: public Worker
{
friend class Session;
friend class HostCapabilityFace;
friend class Node;
friend struct Node;
public:
/// Start server, listening for connections on the given port.
@ -165,6 +172,8 @@ public:
/// Deserialise the data and populate the set of known peers.
void restoreNodes(bytesConstRef _b);
Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; }
void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); }
void start();
@ -191,11 +200,9 @@ private:
/// This won't touch alter the blockchain.
virtual void doWork();
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256());
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256());
Nodes potentialPeers(RangeMask<unsigned> const& _known);
void requestPeers();
std::string m_clientVersion; ///< Our version string.
NetworkPreferences m_netPrefs; ///< Network settings.
@ -211,6 +218,8 @@ private:
bi::tcp::endpoint m_public; ///< Our public listening endpoint.
KeyPair m_key; ///< Our unique ID.
bool m_hadNewNodes = false;
mutable RecursiveMutex x_peers;
/// The nodes to which we are currently connected.
@ -227,8 +236,6 @@ private:
RangeMask<unsigned> m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring.
RangeMask<unsigned> m_private; ///< Indices into m_nodesList over to which nodes are private.
std::chrono::steady_clock::time_point m_lastPeersRequest; ///< Last time we asked for some peers - don't want to do this too often. TODO: peers should be pushed, not polled.
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
// Our addresses.
@ -238,6 +245,8 @@ private:
// Our capabilities.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false;
};

245
libp2p/Session.cpp

@ -40,12 +40,11 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma
m_server(_s),
m_socket(std::move(_socket)),
m_node(nullptr),
m_manualEndpoint(_manual)
m_manualEndpoint(_manual) // NOTE: the port on this shouldn't be used if it's zero.
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
m_lastReceived = m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()});
m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), 0, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()});
}
Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr<Node> const& _n, bool _force):
@ -55,15 +54,15 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr<Node> const&
m_manualEndpoint(_n->address),
m_force(_force)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
m_lastReceived = m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({m_node->id, "?", _n->address.address().to_string(), _n->address.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()});
}
Session::~Session()
{
if (id())
m_server->noteNode(id(), m_manualEndpoint, Origin::Unknown, true);
if (m_node)
if (id() && !isPermanentProblem(m_node->lastDisconnect) && !m_node->dead)
m_server->m_ready += m_node->index;
// Read-chain finished for one reason or another.
for (auto& i: m_capabilities)
@ -125,8 +124,51 @@ template <class T> vector<T> randomSelection(vector<T> const& _t, unsigned _n)
return ret;
}
void Session::ensureNodesRequested()
{
if (isOpen() && !m_weRequestedNodes)
{
m_weRequestedNodes = true;
RLPStream s;
sealAndSend(prep(s, GetPeersPacket));
}
}
void Session::serviceNodesRequest()
{
if (!m_theyRequestedNodes)
return;
auto peers = m_server->potentialPeers(m_knownNodes);
if (peers.empty())
{
addNote("peers", "requested");
return;
}
// note this should cost them...
RLPStream s;
prep(s, PeersPacket, min<unsigned>(10, peers.size()));
auto rs = randomSelection(peers, 10);
for (auto const& i: rs)
{
clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address;
if (i.address.address().is_v4())
s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id;
else// if (i.second.address().is_v6()) - assumed
s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id;
m_knownNodes.extendAll(i.index);
m_knownNodes.unionWith(i.index);
}
sealAndSend(s);
m_theyRequestedNodes = false;
addNote("peers", "done");
}
bool Session::interpret(RLP const& _r)
{
m_lastReceived = chrono::steady_clock::now();
clogS(NetRight) << _r;
try // Generic try-catch block designed to capture RLP format errors - TODO: give decent diagnostics, make a bit more specific over what is caught.
{
@ -135,9 +177,6 @@ bool Session::interpret(RLP const& _r)
{
case HelloPacket:
{
if (m_node)
m_node->lastDisconnect = -1;
m_protocolVersion = _r[1].toInt<unsigned>();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector<CapDesc>();
@ -152,12 +191,12 @@ bool Session::interpret(RLP const& _r)
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;
if (m_server->havePeer(id))
if (m_server->id() == id)
{
// Already connected.
clogS(NetWarn) << "Already connected to a peer with id" << id.abridged();
disconnect(DuplicatePeer);
return false;
clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << m_info.id.abridged();
disconnect(LocalIdentity);
return true;
}
if (m_node && m_node->id != id)
@ -169,14 +208,29 @@ bool Session::interpret(RLP const& _r)
{
clogS(NetWarn) << "Connected to node, but their ID has changed since last time. This could indicate a MitM attack. Disconnecting.";
disconnect(UnexpectedIdentity);
return false;
return true;
}
if (m_server->havePeer(id))
{
m_node->dead = true;
disconnect(DuplicatePeer);
return true;
}
}
if (m_server->havePeer(id))
{
// Already connected.
clogS(NetWarn) << "Already connected to a peer with id" << id.abridged();
disconnect(DuplicatePeer);
return true;
}
if (!id)
{
disconnect(NullIdentity);
return false;
return true;
}
m_node = m_server->noteNode(id, bi::tcp::endpoint(m_socket.remote_endpoint().address(), listenPort), Origin::Self, false, !m_node || m_node->id == id ? NodeId() : m_node->id);
@ -186,7 +240,7 @@ bool Session::interpret(RLP const& _r)
if (m_protocolVersion != m_server->protocolVersion())
{
disconnect(IncompatibleProtocol);
return false;
return true;
}
m_info = PeerInfo({id, clientVersion, m_socket.remote_endpoint().address().to_string(), listenPort, std::chrono::steady_clock::duration(), _r[3].toSet<CapDesc>(), (unsigned)m_socket.native_handle(), map<string, string>() });
@ -196,16 +250,16 @@ bool Session::interpret(RLP const& _r)
case DisconnectPacket:
{
string reason = "Unspecified";
if (_r[1].isInt())
reason = reasonOf((DisconnectReason)_r[1].toInt<int>());
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
auto r = (DisconnectReason)_r[1].toInt<int>();
if (!_r[1].isInt())
drop(BadProtocol);
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
{
reason = reasonOf(r);
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
drop(DisconnectRequested);
}
break;
}
case PingPacket:
{
@ -221,27 +275,13 @@ bool Session::interpret(RLP const& _r)
case GetPeersPacket:
{
clogS(NetTriviaSummary) << "GetPeers";
auto peers = m_server->potentialPeers(m_knownNodes);
if (peers.empty())
break;
RLPStream s;
prep(s, PeersPacket, min<unsigned>(10, peers.size()));
auto rs = randomSelection(peers, 10);
for (auto const& i: rs)
{
clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address;
if (i.address.address().is_v4())
s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id;
else// if (i.second.address().is_v6()) - assumed
s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id;
m_knownNodes.extendAll(i.index);
m_knownNodes.unionWith(i.index);
}
sealAndSend(s);
m_theyRequestedNodes = true;
serviceNodesRequest();
break;
}
case PeersPacket:
clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
m_weRequestedNodes = false;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address peerAddress;
@ -252,7 +292,7 @@ bool Session::interpret(RLP const& _r)
else
{
disconnect(BadProtocol);
return false;
return true;
}
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>());
NodeId id = _r[i][2].toHash<NodeId>();
@ -273,19 +313,29 @@ bool Session::interpret(RLP const& _r)
// check that it's not us or one we already know:
if (m_server->m_nodes.count(id))
{
/* MEH. Far from an ideal solution. Leave alone for now.
// Already got this node.
// See if it's any better that ours or not...
// This could be the public address of a known node.
// SECURITY: remove this in beta - it's only for lazy connections and presents an easy attack vector.
if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()))
if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()) && ep.port() != 0)
// Update address if the node if we now have a public IP for it.
m_server->m_nodes[id]->address = ep;
*/
goto CONTINUE;
}
if (!ep.port())
goto CONTINUE; // Zero port? Don't think so.
if (ep.port() >= 49152)
goto CONTINUE; // Private port according to IANA.
// TODO: PoC-7:
// Technically fine, but ignore for now to avoid peers passing on incoming ports until we can be sure that doesn't happen any more.
// if (ep.port() < 30300 || ep.port() > 30305)
// goto CONTINUE; // Wierd port.
// Avoid our random other addresses that they might end up giving us.
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
@ -314,10 +364,11 @@ bool Session::interpret(RLP const& _r)
}
}
}
catch (...)
catch (std::exception const& _e)
{
clogS(NetWarn) << "Peer causing an exception:" << _e.what();
disconnect(BadProtocol);
return false;
return true;
}
return true;
}
@ -329,12 +380,6 @@ void Session::ping()
m_ping = std::chrono::steady_clock::now();
}
void Session::getPeers()
{
RLPStream s;
sealAndSend(prep(s, GetPeersPacket));
}
RLPStream& Session::prep(RLPStream& _s, PacketType _id, unsigned _args)
{
return prep(_s).appendList(_args + 1).append((unsigned)_id);
@ -350,7 +395,7 @@ void Session::sealAndSend(RLPStream& _s)
bytes b;
_s.swapOut(b);
m_server->seal(b);
sendDestroy(b);
send(move(b));
}
bool Session::checkPacket(bytesConstRef _msg)
@ -368,42 +413,26 @@ bool Session::checkPacket(bytesConstRef _msg)
return true;
}
void Session::sendDestroy(bytes& _msg)
void Session::send(bytesConstRef _msg)
{
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
if (!checkPacket(bytesConstRef(&_msg)))
{
clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(std::move(_msg));
writeImpl(buffer);
send(_msg.toBytes());
}
void Session::send(bytesConstRef _msg)
void Session::send(bytes&& _msg)
{
clogS(NetLeft) << RLP(_msg.cropped(8));
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
if (!checkPacket(_msg))
{
if (!checkPacket(bytesConstRef(&_msg)))
clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(_msg.toBytes());
writeImpl(buffer);
}
void Session::writeImpl(bytes& _buffer)
{
// cerr << (void*)this << " writeImpl" << endl;
if (!m_socket.is_open())
return;
bool doWrite = false;
{
lock_guard<mutex> l(m_writeLock);
m_writeQueue.push_back(_buffer);
Guard l(x_writeQueue);
m_writeQueue.push_back(_msg);
doWrite = (m_writeQueue.size() == 1);
}
@ -417,18 +446,16 @@ void Session::write()
auto self(shared_from_this());
ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/)
{
// cerr << (void*)this << " write.callback" << endl;
// must check queue, as write callback can occur following dropped()
if (ec)
{
clogS(NetWarn) << "Error sending: " << ec.message();
dropped();
drop(TCPError);
return;
}
else
{
lock_guard<mutex> l(m_writeLock);
Guard l(x_writeQueue);
m_writeQueue.pop_front();
if (m_writeQueue.empty())
return;
@ -437,37 +464,43 @@ void Session::write()
});
}
void Session::dropped()
void Session::drop(DisconnectReason _reason)
{
// cerr << (void*)this << " dropped" << endl;
if (m_dropped)
return;
cerr << (void*)this << " dropped" << endl;
if (m_socket.is_open())
try
{
clogS(NetConnect) << "Closing " << m_socket.remote_endpoint();
clogS(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")";
m_socket.close();
}
catch (...) {}
}
void Session::disconnect(int _reason)
{
clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
if (m_node)
{
if (_reason != m_node->lastDisconnect || _reason == NoDisconnect || _reason == ClientQuit || _reason == DisconnectRequested)
m_node->failedAttempts = 0;
m_node->lastDisconnect = _reason;
if (_reason == BadProtocol)
{
m_node->rating /= 2;
m_node->score /= 2;
}
}
m_dropped = true;
}
void Session::disconnect(DisconnectReason _reason)
{
clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")";
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s, DisconnectPacket, 1) << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
else
dropped();
RLPStream s;
prep(s, DisconnectPacket, 1) << (int)_reason;
sealAndSend(s);
}
drop(_reason);
}
void Session::start()
@ -481,15 +514,13 @@ void Session::start()
<< m_server->id();
sealAndSend(s);
ping();
getPeers();
doRead();
}
void Session::doRead()
{
// ignore packets received while waiting to disconnect
if (chrono::steady_clock::now() - m_disconnect > chrono::seconds(0))
if (m_dropped)
return;
auto self(shared_from_this());
@ -500,7 +531,7 @@ void Session::doRead()
{
// got here with length of 1241...
clogS(NetWarn) << "Error reading: " << ec.message();
dropped();
drop(TCPError);
}
else if (ec && length == 0)
{
@ -541,8 +572,8 @@ void Session::doRead()
RLP r(data.cropped(8));
if (!interpret(r))
{
// error
dropped();
// error - bad protocol
disconnect(BadProtocol);
return;
}
}
@ -555,12 +586,12 @@ void Session::doRead()
catch (Exception const& _e)
{
clogS(NetWarn) << "ERROR: " << diagnostic_information(_e);
dropped();
drop(BadProtocol);
}
catch (std::exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.what();
dropped();
drop(BadProtocol);
}
}
});

57
libp2p/Session.h

@ -30,6 +30,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Guards.h>
#include "Common.h"
namespace dev
@ -38,7 +39,7 @@ namespace dev
namespace p2p
{
class Node;
struct Node;
/**
* @brief The Session class
@ -55,7 +56,7 @@ public:
virtual ~Session();
void start();
void disconnect(int _reason);
void disconnect(DisconnectReason _reason);
void ping();
@ -72,7 +73,7 @@ public:
static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytes&& _msg);
void send(bytesConstRef _msg);
int rating() const;
@ -82,42 +83,50 @@ public:
PeerInfo const& info() const { return m_info; }
void ensureNodesRequested();
void serviceNodesRequest();
private:
void dropped();
/// Drop the connection for the reason @a _r.
void drop(DisconnectReason _r);
/// Perform a read on the socket.
void doRead();
void doWrite(std::size_t length);
void writeImpl(bytes& _buffer);
/// Perform a single round of the write operation. This could end up calling itself asynchronously.
void write();
void getPeers();
/// Interpret an incoming message.
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
Host* m_server;
Host* m_server; ///< The host that owns us. Never null.
std::mutex m_writeLock;
std::deque<bytes> m_writeQueue;
mutable bi::tcp::socket m_socket; ///< Socket for the peer's connection. Mutable to ask for native_handle().
Mutex x_writeQueue; ///< Mutex for the write queue.
std::deque<bytes> m_writeQueue; ///< The write queue.
std::array<byte, 65536> m_data; ///< Data buffer for the write queue.
bytes m_incoming; ///< The incoming read queue of bytes.
mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().
std::array<byte, 65536> m_data;
PeerInfo m_info;
PeerInfo m_info; ///< Dyanamic information about this peer.
bytes m_incoming;
unsigned m_protocolVersion;
std::shared_ptr<Node> m_node;
bi::tcp::endpoint m_manualEndpoint;
bool m_force = false; /// If true, ignore IDs being different. This could open you up to MitM attacks.
unsigned m_protocolVersion = 0; ///< The protocol version of the peer.
std::shared_ptr<Node> m_node; ///< The Node object. Might be null if we constructed using a bare address/port.
bi::tcp::endpoint m_manualEndpoint; ///< The endpoint as specified by the constructor.
bool m_force = false; ///< If true, ignore IDs being different. This could open you up to MitM attacks.
bool m_dropped = false; ///< If true, we've already divested ourselves of this peer. We're just waiting for the reads & writes to fail before the shared_ptr goes OOS and the destructor kicks in.
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us?
bool m_weRequestedNodes = false; ///< Have we requested nodes from the peer and not received an answer yet?
std::map<CapDesc, std::shared_ptr<Capability>> m_capabilities;
RangeMask<unsigned> m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer.
std::chrono::steady_clock::time_point m_connect; ///< Time point of connection.
std::chrono::steady_clock::time_point m_ping; ///< Time point of last ping.
std::chrono::steady_clock::time_point m_lastReceived; ///< Time point of last message.
bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand.
std::map<CapDesc, std::shared_ptr<Capability>> m_capabilities; ///< The peer's capability set.
RangeMask<unsigned> m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer.
};
}

2
libqethereum/QEthereum.cpp

@ -396,7 +396,7 @@ static QString toJson(dev::eth::Transaction const& _bi)
v["from"] = toQJS(_bi.sender());
v["gas"] = (int)_bi.gas;
v["gasPrice"] = toQJS(_bi.gasPrice);
v["nonce"] = toQJS(_bi.nonce);
v["nonce"] = (int)_bi.nonce;
v["value"] = toQJS(_bi.value);
return QString::fromUtf8(QJsonDocument(v).toJson());

5
libwebthree/WebThree.h

@ -108,6 +108,11 @@ public:
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
p2p::NodeId id() const { return m_net.id(); }
/// Gets the nodes.
p2p::Nodes nodes() const { return m_net.nodes(); }
/// Start the network subsystem.
void startNetwork() { m_net.start(); }

Loading…
Cancel
Save