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

Commit 8771c9a

Browse files
committed
Add support for updating ENR
1 parent 7ecf42b commit 8771c9a

File tree

7 files changed

+79
-32
lines changed

7 files changed

+79
-32
lines changed

libp2p/ENR.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace p2p
1212
namespace
1313
{
1414
constexpr char c_keyID[] = "id";
15-
constexpr char c_keySec256k1[] = "secp256k1";
15+
constexpr char c_keySecp256k1[] = "secp256k1";
1616
constexpr char c_keyIP[] = "ip";
1717
constexpr char c_keyTCP[] = "tcp";
1818
constexpr char c_keyUDP[] = "udp";
@@ -88,29 +88,57 @@ void ENR::streamContent(RLPStream& _s) const
8888
}
8989
}
9090

91-
ENR createV4ENR(Secret const& _secret, boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
91+
ENR ENR::update(
92+
std::map<std::string, bytes> const& _keyValuePairs, SignFunction const& _signFunction) const
9293
{
93-
ENR::SignFunction signFunction = [&_secret](bytesConstRef _data) {
94-
// dev::sign returns 65 bytes signature containing r,s,v values
95-
Signature s = dev::sign(_secret, sha3(_data));
96-
// The resulting 64-byte signature is encoded as the concatenation of the r and s signature values.
97-
return bytes(&s[0], &s[64]);
98-
};
94+
return ENR(m_seq + 1, _keyValuePairs, _signFunction);
95+
}
96+
97+
ENR IdentitySchemeV4::createENR(Secret const& _secret, boost::asio::ip::address const& _ip,
98+
uint16_t _tcpPort, uint16_t _udpPort)
99+
{
100+
ENR::SignFunction signFunction = [&_secret](
101+
bytesConstRef _data) { return sign(_data, _secret); };
102+
103+
auto const keyValuePairs = createKeyValuePairs(_secret, _ip, _tcpPort, _udpPort);
99104

105+
return ENR{0 /* sequence number */, keyValuePairs, signFunction};
106+
}
107+
108+
bytes IdentitySchemeV4::sign(bytesConstRef _data, Secret const& _secret)
109+
{
110+
// dev::sign returns 65 bytes signature containing r,s,v values
111+
Signature s = dev::sign(_secret, sha3(_data));
112+
// The resulting 64-byte signature is encoded as the concatenation of the r and s signature
113+
// values.
114+
return bytes(&s[0], &s[64]);
115+
}
116+
117+
std::map<std::string, bytes> IdentitySchemeV4::createKeyValuePairs(Secret const& _secret,
118+
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
119+
{
100120
PublicCompressed const publicKey = toPublicCompressed(_secret);
101121

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

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

110-
return ENR{0 /* sequence number */, keyValuePairs, signFunction};
130+
ENR IdentitySchemeV4::updateENR(ENR const& _enr, Secret const& _secret,
131+
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort)
132+
{
133+
ENR::SignFunction signFunction = [&_secret](
134+
bytesConstRef _data) { return sign(_data, _secret); };
135+
136+
auto const keyValuePairs = createKeyValuePairs(_secret, _ip, _tcpPort, _udpPort);
137+
138+
return _enr.update(keyValuePairs, signFunction);
111139
}
112140

113-
ENR parseV4ENR(RLP const& _rlp)
141+
ENR IdentitySchemeV4::parseENR(RLP const& _rlp)
114142
{
115143
ENR::VerifyFunction verifyFunction = [](std::map<std::string, bytes> const& _keyValuePairs,
116144
bytesConstRef _signature, bytesConstRef _data) {

libp2p/ENR.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class ENR
4141
// Serialize to given RLP stream
4242
void streamRLP(RLPStream& _s) const;
4343

44+
// Create new ENR succeeding current one with updated keyValuePairs
45+
ENR update(
46+
std::map<std::string, bytes> const& _keyValuePair, SignFunction const& _signFunction) const;
47+
4448
private:
4549
uint64_t m_seq = 0;
4650
std::map<std::string, bytes> m_map;
@@ -51,10 +55,22 @@ class ENR
5155
void streamContent(RLPStream& _s) const;
5256
};
5357

58+
class IdentitySchemeV4
59+
{
60+
public:
61+
static ENR createENR(Secret const& _secret, boost::asio::ip::address const& _ip,
62+
uint16_t _tcpPort, uint16_t _udpPort);
63+
64+
static ENR updateENR(ENR const& _enr, Secret const& _secret,
65+
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort);
5466

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

57-
ENR parseV4ENR(RLP const& _rlp);
69+
private:
70+
static bytes sign(bytesConstRef _data, Secret const& _secret);
71+
static std::map<std::string, bytes> createKeyValuePairs(Secret const& _secret,
72+
boost::asio::ip::address const& _ip, uint16_t _tcpPort, uint16_t _udpPort);
73+
};
5874

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

libp2p/Host.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ std::pair<Secret, ENR> Host::restoreENR(bytesConstRef _b, NetworkConfig const& _
10241024
secret = Secret{r[1][0].toBytes()};
10251025
auto enrRlp = r[1][1];
10261026

1027-
return make_pair(secret, parseV4ENR(enrRlp));
1027+
return make_pair(secret, IdentitySchemeV4::parseENR(enrRlp));
10281028
}
10291029

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

10481048
bool Host::nodeTableHasNode(Public const& _id) const

libp2p/NodeTable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ struct ENRResponse : DiscoveryDatagram
653653
{
654654
RLP r(_bytes, RLP::AllowNonCanon | RLP::ThrowOnFail);
655655
echo = (h256)r[0];
656-
enr.reset(new ENR{parseV4ENR(r[1])});
656+
enr.reset(new ENR{IdentitySchemeV4::parseENR(r[1])});
657657
}
658658

659659
std::string typeName() const override { return "ENRResponse"; }

test/unittests/libp2p/ENRTest.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ TEST(enr, parse)
2727
"f884b8407098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f3"
2828
"0813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c01826964827634826970847f00000189736563703235"
2929
"366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31388375647082765f");
30-
ENR enr = parseV4ENR(RLP{rlp});
30+
ENR enr = IdentitySchemeV4::parseENR(RLP{rlp});
3131

3232
EXPECT_EQ(enr.signature(),
3333
fromHex("7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f3"
@@ -45,13 +45,14 @@ TEST(enr, createAndParse)
4545
{
4646
auto keyPair = KeyPair::create();
4747

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

5051
RLPStream s;
5152
enr1.streamRLP(s);
5253
bytes rlp = s.out();
5354

54-
ENR enr2 = parseV4ENR(RLP{rlp});
55+
ENR enr2 = IdentitySchemeV4::parseENR(RLP{rlp});
5556

5657
EXPECT_EQ(enr1.signature(), enr2.signature());
5758
EXPECT_EQ(enr1.sequenceNumber(), enr2.sequenceNumber());
@@ -110,7 +111,8 @@ TEST(enr, parseInvalidSignature)
110111
{
111112
auto keyPair = KeyPair::create();
112113

113-
ENR enr1 = createV4ENR(keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
114+
ENR enr1 = IdentitySchemeV4::createENR(
115+
keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
114116

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

123-
EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
125+
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
124126
}
125127

126128
TEST(enr, parseV4WithInvalidID)
@@ -133,7 +135,7 @@ TEST(enr, parseV4WithInvalidID)
133135
enr1.streamRLP(s);
134136
bytes rlp = s.out();
135137

136-
EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
138+
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
137139
}
138140

139141
TEST(enr, parseV4WithNoPublicKey)
@@ -146,13 +148,14 @@ TEST(enr, parseV4WithNoPublicKey)
146148
enr1.streamRLP(s);
147149
bytes rlp = s.out();
148150

149-
EXPECT_THROW(parseV4ENR(RLP{rlp}), ENRSignatureIsInvalid);
151+
EXPECT_THROW(IdentitySchemeV4::parseENR(RLP{rlp}), ENRSignatureIsInvalid);
150152
}
151153

152154
TEST(enr, createV4)
153155
{
154156
auto keyPair = KeyPair::create();
155-
ENR enr = createV4ENR(keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
157+
ENR enr = IdentitySchemeV4::createENR(
158+
keyPair.secret(), bi::address::from_string("127.0.0.1"), 3322, 5544);
156159

157160
auto keyValuePairs = enr.keyValuePairs();
158161

test/unittests/libp2p/eip-8.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,8 @@ shared_ptr<TestHandshake> TestHandshake::runWithInput(
378378
});
379379

380380
// Spawn a client to execute the handshake.
381-
auto host = make_shared<Host>(
382-
"peer name", make_pair(_hostAlias, createV4ENR(_hostAlias, endpoint.address(), 0, 0)));
381+
auto host = make_shared<Host>("peer name",
382+
make_pair(_hostAlias, IdentitySchemeV4::createENR(_hostAlias, endpoint.address(), 0, 0)));
383383
auto client = make_shared<RLPXSocket>(io);
384384
shared_ptr<TestHandshake> handshake;
385385
if (_remoteID == NodeID())

test/unittests/libp2p/net.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ struct TestNodeTable: public NodeTable
4848
TestNodeTable(
4949
ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30311)
5050
: NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port),
51-
createV4ENR(_alias.secret(), _addr, _port, _port), true /* discovery enabled */,
52-
true /* allow local discovery */)
51+
IdentitySchemeV4::createENR(_alias.secret(), _addr, _port, _port),
52+
true /* discovery enabled */, true /* allow local discovery */)
5353
{}
5454

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

0 commit comments

Comments
 (0)