Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Add support for updating ENR
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed May 9, 2019
1 parent 7ecf42b commit 8771c9a
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 32 deletions.
54 changes: 41 additions & 13 deletions libp2p/ENR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace p2p
namespace
{
constexpr char c_keyID[] = "id";
constexpr char c_keySec256k1[] = "secp256k1";
constexpr char c_keySecp256k1[] = "secp256k1";
constexpr char c_keyIP[] = "ip";
constexpr char c_keyTCP[] = "tcp";
constexpr char c_keyUDP[] = "udp";
Expand Down Expand Up @@ -88,29 +88,57 @@ void ENR::streamContent(RLPStream& _s) const
}
}

ENR createV4ENR(Secret const& _secret, boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
ENR ENR::update(
std::map<std::string, bytes> const& _keyValuePairs, SignFunction const& _signFunction) const
{
ENR::SignFunction signFunction = [&_secret](bytesConstRef _data) {
// dev::sign returns 65 bytes signature containing r,s,v values
Signature s = dev::sign(_secret, sha3(_data));
// The resulting 64-byte signature is encoded as the concatenation of the r and s signature values.
return bytes(&s[0], &s[64]);
};
return ENR(m_seq + 1, _keyValuePairs, _signFunction);
}

ENR IdentitySchemeV4::createENR(Secret const& _secret, boost::asio::ip::address const& _ip,
uint16_t _tcpPort, uint16_t _udpPort)
{
ENR::SignFunction signFunction = [&_secret](
bytesConstRef _data) { return sign(_data, _secret); };

auto const keyValuePairs = createKeyValuePairs(_secret, _ip, _tcpPort, _udpPort);

return ENR{0 /* sequence number */, keyValuePairs, signFunction};
}

bytes IdentitySchemeV4::sign(bytesConstRef _data, Secret const& _secret)
{
// dev::sign returns 65 bytes signature containing r,s,v values
Signature s = dev::sign(_secret, sha3(_data));
// The resulting 64-byte signature is encoded as the concatenation of the r and s signature
// values.
return bytes(&s[0], &s[64]);
}

std::map<std::string, bytes> IdentitySchemeV4::createKeyValuePairs(Secret const& _secret,
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
{
PublicCompressed const publicKey = toPublicCompressed(_secret);

auto const address = _ip.is_v4() ? addressToBytes(_ip.to_v4()) : addressToBytes(_ip.to_v6());

// Values are of different types (string, bytes, uint16_t),
// so we store them as RLP representation
std::map<std::string, bytes> const keyValuePairs = {{c_keyID, rlp(c_IDV4)},
{c_keySec256k1, rlp(publicKey.asBytes())}, {c_keyIP, rlp(address)},
{c_keyTCP, rlp(_tcpPort)}, {c_keyUDP, rlp(_udpPort)}};
return {{c_keyID, rlp(c_IDV4)}, {c_keySecp256k1, rlp(publicKey.asBytes())},
{c_keyIP, rlp(address)}, {c_keyTCP, rlp(_tcpPort)}, {c_keyUDP, rlp(_udpPort)}};
}

return ENR{0 /* sequence number */, keyValuePairs, signFunction};
ENR IdentitySchemeV4::updateENR(ENR const& _enr, Secret const& _secret,
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
{
ENR::SignFunction signFunction = [&_secret](
bytesConstRef _data) { return sign(_data, _secret); };

auto const keyValuePairs = createKeyValuePairs(_secret, _ip, _tcpPort, _udpPort);

return _enr.update(keyValuePairs, signFunction);
}

ENR parseV4ENR(RLP const& _rlp)
ENR IdentitySchemeV4::parseENR(RLP const& _rlp)
{
ENR::VerifyFunction verifyFunction = [](std::map<std::string, bytes> const& _keyValuePairs,
bytesConstRef _signature, bytesConstRef _data) {
Expand Down
20 changes: 18 additions & 2 deletions libp2p/ENR.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class ENR
// Serialize to given RLP stream
void streamRLP(RLPStream& _s) const;

// Create new ENR succeeding current one with updated keyValuePairs
ENR update(
std::map<std::string, bytes> const& _keyValuePair, SignFunction const& _signFunction) const;

private:
uint64_t m_seq = 0;
std::map<std::string, bytes> m_map;
Expand All @@ -51,10 +55,22 @@ class ENR
void streamContent(RLPStream& _s) const;
};

class IdentitySchemeV4
{
public:
static ENR createENR(Secret const& _secret, boost::asio::ip::address const& _ip,
uint16_t _tcpPort, uint16_t _udpPort);

static ENR updateENR(ENR const& _enr, Secret const& _secret,
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort);

ENR createV4ENR(Secret const& _secret, boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort);
static ENR parseENR(RLP const& _rlp);

ENR parseV4ENR(RLP const& _rlp);
private:
static bytes sign(bytesConstRef _data, Secret const& _secret);
static std::map<std::string, bytes> createKeyValuePairs(Secret const& _secret,
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort);
};

std::ostream& operator<<(std::ostream& _out, ENR const& _enr);

Expand Down
6 changes: 3 additions & 3 deletions libp2p/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ std::pair<Secret, ENR> Host::restoreENR(bytesConstRef _b, NetworkConfig const& _
secret = Secret{r[1][0].toBytes()};
auto enrRlp = r[1][1];

return make_pair(secret, parseV4ENR(enrRlp));
return make_pair(secret, IdentitySchemeV4::parseENR(enrRlp));
}

// Support for older format without ENR
Expand All @@ -1041,8 +1041,8 @@ std::pair<Secret, ENR> Host::restoreENR(bytesConstRef _b, NetworkConfig const& _
auto const address = _netConfig.publicIPAddress.empty() ?
bi::address{} :
bi::address::from_string(_netConfig.publicIPAddress);
return make_pair(
secret, createV4ENR(secret, address, _netConfig.listenPort, _netConfig.listenPort));
return make_pair(secret,
IdentitySchemeV4::createENR(secret, address, _netConfig.listenPort, _netConfig.listenPort));
}

bool Host::nodeTableHasNode(Public const& _id) const
Expand Down
2 changes: 1 addition & 1 deletion libp2p/NodeTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ struct ENRResponse : DiscoveryDatagram
{
RLP r(_bytes, RLP::AllowNonCanon | RLP::ThrowOnFail);
echo = (h256)r[0];
enr.reset(new ENR{parseV4ENR(r[1])});
enr.reset(new ENR{IdentitySchemeV4::parseENR(r[1])});
}

std::string typeName() const override { return "ENRResponse"; }
Expand Down
19 changes: 11 additions & 8 deletions test/unittests/libp2p/ENRTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ TEST(enr, parse)
"f884b8407098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f3"
"0813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c01826964827634826970847f00000189736563703235"
"366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31388375647082765f");
ENR enr = parseV4ENR(RLP{rlp});
ENR enr = IdentitySchemeV4::parseENR(RLP{rlp});

EXPECT_EQ(enr.signature(),
fromHex("7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f3"
Expand All @@ -45,13 +45,14 @@ TEST(enr, createAndParse)
{
auto keyPair = KeyPair::create();

ENR enr1 = createV4ENR(keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
ENR enr1 = IdentitySchemeV4::createENR(
keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);

RLPStream s;
enr1.streamRLP(s);
bytes rlp = s.out();

ENR enr2 = parseV4ENR(RLP{rlp});
ENR enr2 = IdentitySchemeV4::parseENR(RLP{rlp});

EXPECT_EQ(enr1.signature(), enr2.signature());
EXPECT_EQ(enr1.sequenceNumber(), enr2.sequenceNumber());
Expand Down Expand Up @@ -110,7 +111,8 @@ TEST(enr, parseInvalidSignature)
{
auto keyPair = KeyPair::create();

ENR enr1 = createV4ENR(keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
ENR enr1 = IdentitySchemeV4::createENR(
keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);

RLPStream s;
enr1.streamRLP(s);
Expand All @@ -120,7 +122,7 @@ TEST(enr, parseInvalidSignature)
auto signatureOffset = RLP{rlp}[0].payload().data() - rlp.data();
rlp[signatureOffset]++;

EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
}

TEST(enr, parseV4WithInvalidID)
Expand All @@ -133,7 +135,7 @@ TEST(enr, parseV4WithInvalidID)
enr1.streamRLP(s);
bytes rlp = s.out();

EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
}

TEST(enr, parseV4WithNoPublicKey)
Expand All @@ -146,13 +148,14 @@ TEST(enr, parseV4WithNoPublicKey)
enr1.streamRLP(s);
bytes rlp = s.out();

EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
}

TEST(enr, createV4)
{
auto keyPair = KeyPair::create();
ENR enr = createV4ENR(keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
ENR enr = IdentitySchemeV4::createENR(
keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);

auto keyValuePairs = enr.keyValuePairs();

Expand Down
4 changes: 2 additions & 2 deletions test/unittests/libp2p/eip-8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ shared_ptr<TestHandshake> TestHandshake::runWithInput(
});

// Spawn a client to execute the handshake.
auto host = make_shared<Host>(
"peer name", make_pair(_hostAlias, createV4ENR(_hostAlias, endpoint.address(), 0, 0)));
auto host = make_shared<Host>("peer name",
make_pair(_hostAlias, IdentitySchemeV4::createENR(_hostAlias, endpoint.address(), 0, 0)));
auto client = make_shared<RLPXSocket>(io);
shared_ptr<TestHandshake> handshake;
if (_remoteID == NodeID())
Expand Down
6 changes: 3 additions & 3 deletions test/unittests/libp2p/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ struct TestNodeTable: public NodeTable
TestNodeTable(
ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30311)
: NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port),
createV4ENR(_alias.secret(), _addr, _port, _port), true /* discovery enabled */,
true /* allow local discovery */)
IdentitySchemeV4::createENR(_alias.secret(), _addr, _port, _port),
true /* discovery enabled */, true /* allow local discovery */)
{}

static vector<pair<Public, uint16_t>> createTestNodes(unsigned _count)
Expand Down Expand Up @@ -1429,7 +1429,7 @@ BOOST_AUTO_TEST_CASE(nodeTableReturnsUnspecifiedNode)
auto const keyPair = KeyPair::create();
auto const addr = bi::address::from_string(c_localhostIp);
NodeTable t(io, keyPair, NodeIPEndpoint(addr, port, port),
createV4ENR(keyPair.secret(), addr, port, port));
IdentitySchemeV4::createENR(keyPair.secret(), addr, port, port));
if (Node n = t.node(NodeID()))
BOOST_REQUIRE(false);
}
Expand Down

0 comments on commit 8771c9a

Please sign in to comment.