-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Discovery ENR extension - server part #5571
Changes from 8 commits
6510471
628afb5
62c00d1
aecf6e4
4bbe854
92210a0
dd22aad
c62cb8a
28dc37e
6f15106
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,9 +32,10 @@ inline bool operator==(weak_ptr<NodeEntry> const& _weak, shared_ptr<NodeEntry> c | |
} | ||
|
||
NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, | ||
bool _enabled, bool _allowLocalDiscovery) | ||
ENR const& _enr, bool _enabled, bool _allowLocalDiscovery) | ||
: m_hostNodeID{_alias.pub()}, | ||
m_hostNodeEndpoint{_endpoint}, | ||
m_hostENR{_enr}, | ||
m_secret{_alias.secret()}, | ||
m_socket{make_shared<NodeSocket>( | ||
_io, static_cast<UDPSocketEvents&>(*this), (bi::udp::endpoint)m_hostNodeEndpoint)}, | ||
|
@@ -220,7 +221,7 @@ void NodeTable::doDiscoveryRound( | |
} | ||
|
||
FindNode p(nodeEntry->endpoint(), _node); | ||
p.ts = nextRequestExpirationTime(); | ||
p.timestamp = nextRequestExpirationTime(); | ||
p.sign(m_secret); | ||
m_sentFindNodes.emplace_back(nodeEntry->id(), chrono::steady_clock::now()); | ||
LOG(m_logger) << p.typeName() << " to " << nodeEntry->node << " (target: " << _node | ||
|
@@ -302,7 +303,8 @@ void NodeTable::ping(Node const& _node, shared_ptr<NodeEntry> _replacementNodeEn | |
} | ||
|
||
PingNode p{m_hostNodeEndpoint, _node.endpoint}; | ||
p.ts = nextRequestExpirationTime(); | ||
p.timestamp = nextRequestExpirationTime(); | ||
p.seq = m_hostENR.sequenceNumber(); | ||
auto const pingHash = p.sign(m_secret); | ||
LOG(m_logger) << p.typeName() << " to " << _node; | ||
m_socket->send(p); | ||
|
@@ -454,6 +456,14 @@ void NodeTable::onPacketReceived( | |
case PingNode::type: | ||
sourceNodeEntry = handlePingNode(_from, *packet); | ||
break; | ||
|
||
case ENRRequest::type: | ||
sourceNodeEntry = handleENRRequest(_from, *packet); | ||
break; | ||
|
||
case ENRResponse::type: | ||
sourceNodeEntry = handleENRResponse(_from, *packet); | ||
break; | ||
} | ||
|
||
if (sourceNodeEntry) | ||
|
@@ -608,7 +618,7 @@ std::shared_ptr<NodeEntry> NodeTable::handleFindNode( | |
for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) | ||
{ | ||
Neighbours out(_from, nearest, offset, nlimit); | ||
out.ts = nextRequestExpirationTime(); | ||
out.timestamp = nextRequestExpirationTime(); | ||
LOG(m_logger) << out.typeName() << " to " << in.sourceid << "@" << _from; | ||
out.sign(m_secret); | ||
if (out.data.size() > 1280) | ||
|
@@ -631,8 +641,9 @@ std::shared_ptr<NodeEntry> NodeTable::handlePingNode( | |
// Send PONG response. | ||
Pong p(sourceEndpoint); | ||
LOG(m_logger) << p.typeName() << " to " << in.sourceid << "@" << _from; | ||
p.ts = nextRequestExpirationTime(); | ||
p.timestamp = nextRequestExpirationTime(); | ||
p.echo = in.echo; | ||
p.seq = m_hostENR.sequenceNumber(); | ||
p.sign(m_secret); | ||
m_socket->send(p); | ||
|
||
|
@@ -647,6 +658,69 @@ std::shared_ptr<NodeEntry> NodeTable::handlePingNode( | |
return sourceNodeEntry; | ||
} | ||
|
||
std::shared_ptr<NodeEntry> NodeTable::handleENRRequest( | ||
bi::udp::endpoint const& _from, DiscoveryDatagram const& _packet) | ||
{ | ||
std::shared_ptr<NodeEntry> sourceNodeEntry = nodeEntry(_packet.sourceid); | ||
if (!sourceNodeEntry) | ||
{ | ||
LOG(m_logger) << "Source node (" << _packet.sourceid << "@" << _from | ||
<< ") not found in node table. Ignoring ENRRequest request."; | ||
return {}; | ||
} | ||
if (sourceNodeEntry->endpoint() != _from) | ||
{ | ||
LOG(m_logger) << "ENRRequest packet from unexpected endpoint " << _from << " instead of " | ||
halfalicious marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<< sourceNodeEntry->endpoint(); | ||
halfalicious marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return {}; | ||
} | ||
if (!sourceNodeEntry->lastPongReceivedTime) | ||
{ | ||
LOG(m_logger) << "Unexpected ENRRequest packet! Endpoint proof hasn't been performed yet."; | ||
return {}; | ||
} | ||
if (!sourceNodeEntry->hasValidEndpointProof()) | ||
{ | ||
LOG(m_logger) << "Unexpected ENRRequest packet! Endpoint proof has expired."; | ||
return {}; | ||
} | ||
|
||
auto const& in = dynamic_cast<ENRRequest const&>(_packet); | ||
|
||
ENRResponse response{_from, m_hostENR}; | ||
LOG(m_logger) << response.typeName() << " to " << in.sourceid << "@" << _from; | ||
response.timestamp = nextRequestExpirationTime(); | ||
response.echo = in.echo; | ||
response.sign(m_secret); | ||
m_socket->send(response); | ||
|
||
return sourceNodeEntry; | ||
} | ||
|
||
std::shared_ptr<NodeEntry> NodeTable::handleENRResponse( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should verify the hash in the response against the request (or are you planning on doing that in another change)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I planned to add the validation when implementing doing something useful with these responses (the last "ENR Client" part in #5551) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we listen for responses I think we should validate them so there's 1 less thing to do when we want to actually do something useful with them. |
||
bi::udp::endpoint const& _from, DiscoveryDatagram const& _packet) | ||
{ | ||
std::shared_ptr<NodeEntry> sourceNodeEntry = nodeEntry(_packet.sourceid); | ||
if (!sourceNodeEntry) | ||
{ | ||
LOG(m_logger) << "Source node (" << _packet.sourceid << "@" << _from | ||
<< ") not found in node table. Ignoring ENRResponse packet."; | ||
return {}; | ||
} | ||
if (sourceNodeEntry->endpoint() != _from) | ||
{ | ||
LOG(m_logger) << "ENRResponse packet from unexpected endpoint " << _from << " instead of " | ||
gumb0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<< sourceNodeEntry->endpoint(); | ||
return {}; | ||
} | ||
|
||
auto const& in = dynamic_cast<ENRResponse const&>(_packet); | ||
LOG(m_logger) << "Received ENR: " << *in.enr; | ||
|
||
return sourceNodeEntry; | ||
} | ||
|
||
|
||
void NodeTable::doDiscovery() | ||
{ | ||
m_discoveryTimer->expires_from_now(c_bucketRefreshMs); | ||
|
@@ -766,6 +840,12 @@ unique_ptr<DiscoveryDatagram> DiscoveryDatagram::interpretUDP(bi::udp::endpoint | |
case Neighbours::type: | ||
decoded.reset(new Neighbours(_from, sourceid, echo)); | ||
break; | ||
case ENRRequest::type: | ||
decoded.reset(new ENRRequest(_from, sourceid, echo)); | ||
break; | ||
case ENRResponse::type: | ||
decoded.reset(new ENRResponse(_from, sourceid, echo)); | ||
break; | ||
default: | ||
LOG(g_discoveryWarnLogger::get()) << "Invalid packet (unknown packet type) from " | ||
<< _from.address().to_string() << ":" << _from.port(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
geth's similar code for reference: https://github.com/ethereum/go-ethereum/blob/c4109d790ffd26d67feb7745d4af8a8bc5090bd9/crypto/secp256k1/ext.h#L76-L90