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

Outputs ENR text representation in admin.nodeInfo RPC #5701

Merged
merged 5 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Added: [#5634](https://github.com/ethereum/aleth/pull/5634) Bootnodes for Rinkeby and Goerli.
- Added: [#5640](https://github.com/ethereum/aleth/pull/5640) Istanbul support: EIP-1702 Generalized Account Versioning Scheme.
- Added: [#5690](https://github.com/ethereum/aleth/issues/5690) Istanbul support: EIP-2028 transaction data gas cost reduction.
- Added: [#5701](https://github.com/ethereum/aleth/issues/5701) Outputs ENR text representation in admin.nodeInfo RPC.
- Changed: [#5532](https://github.com/ethereum/aleth/pull/5532) The leveldb is upgraded to 1.22. This is breaking change on Windows and the old databases are not compatible.
- Changed: [#5559](https://github.com/ethereum/aleth/pull/5559) Update peer validation error messages.
- Changed: [#5568](https://github.com/ethereum/aleth/pull/5568) Improve rlpx handshake log messages and create new rlpx log channel.
Expand Down
219 changes: 117 additions & 102 deletions libdevcore/Base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
freely, subject to the following restrictions:

1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
misrepresented as being the original source code.

3. This notice may not be removed or altered from any source distribution.

Expand All @@ -33,114 +33,129 @@ using namespace dev;

static inline bool is_base64(byte c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
return (isalnum(c) || (c == '+') || (c == '/'));
}

static inline byte find_base64_char_index(byte c)
{
if ('A' <= c && c <= 'Z') return c - 'A';
else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z');
else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z');
else if (c == '+') return 1 + find_base64_char_index('9');
else if (c == '/') return 1 + find_base64_char_index('+');
else return 1 + find_base64_char_index('/');
if ('A' <= c && c <= 'Z') return c - 'A';
else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z');
else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z');
else if (c == '+') return 1 + find_base64_char_index('9');
else if (c == '/') return 1 + find_base64_char_index('+');
else return 1 + find_base64_char_index('/');
}

string toBase64Encoding(bytesConstRef _in, char const* _base64_chars, bool _pad)
{
string ret;
int i = 0;
int j = 0;
byte char_array_3[3];
byte char_array_4[4];

auto buf = _in.data();
auto bufLen = _in.size();

while (bufLen--)
{
char_array_3[i++] = *(buf++);
if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for (i = 0; i < 4; i++)
ret += _base64_chars[char_array_4[i]];
i = 0;
}
}

if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';

char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for (j = 0; j < i + 1; j++)
ret += _base64_chars[char_array_4[j]];

while (i++ < 3 && _pad)
ret += '=';
}

return ret;
}

string dev::toBase64(bytesConstRef _in)
{
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

string ret;
int i = 0;
int j = 0;
byte char_array_3[3];
byte char_array_4[4];

auto buf = _in.data();
auto bufLen = _in.size();

while (bufLen--)
{
char_array_3[i++] = *(buf++);
if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for (i = 0; i < 4; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}

if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';

char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for (j = 0; j < i + 1; j++)
ret += base64_chars[char_array_4[j]];

while (i++ < 3)
ret += '=';
}

return ret;
static char const c_base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
bool const pad = true;
return toBase64Encoding(_in, c_base64_chars, pad);
}

string dev::toBase64URLSafe(bytesConstRef _in)
{
static char const c_base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_";
bool const pad = false;
return toBase64Encoding(_in, c_base64_chars, pad);
}

bytes dev::fromBase64(string const& encoded_string)
{
auto in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
byte char_array_3[3];
byte char_array_4[4];
bytes ret;

while (in_len-- && encoded_string[in_] != '=' && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4)
{
for (i = 0; i < 4; i++)
char_array_4[i] = find_base64_char_index(char_array_4[i]);

char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

for (i = 0; (i < 3); i++)
ret.push_back(char_array_3[i]);
i = 0;
}
}

if (i)
{
for (j = i; j < 4; j++)
char_array_4[j] = 0;

for (j = 0; j < 4; j++)
char_array_4[j] = find_base64_char_index(char_array_4[j]);

char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

for (j = 0; j < i - 1; j++)
ret.push_back(char_array_3[j]);
}

return ret;
auto in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
byte char_array_3[3];
byte char_array_4[4];
bytes ret;

while (in_len-- && encoded_string[in_] != '=' && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4)
{
for (i = 0; i < 4; i++)
char_array_4[i] = find_base64_char_index(char_array_4[i]);

char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

for (i = 0; (i < 3); i++)
ret.push_back(char_array_3[i]);
i = 0;
}
}

if (i)
{
for (j = i; j < 4; j++)
char_array_4[j] = 0;

for (j = 0; j < 4; j++)
char_array_4[j] = find_base64_char_index(char_array_4[j]);

char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

for (j = 0; j < i - 1; j++)
ret.push_back(char_array_3[j]);
}

return ret;
}
14 changes: 7 additions & 7 deletions libdevcore/Base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
freely, subject to the following restrictions:

1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
misrepresented as being the original source code.

3. This notice may not be removed or altered from any source distribution.

Expand All @@ -28,13 +28,13 @@
/// DEVified by Gav Wood.
#pragma once

#include <string>
#include "FixedHash.h"
#include <string>

namespace dev
{

std::string toBase64(bytesConstRef _in);
std::string toBase64URLSafe(bytesConstRef _in);
bytes fromBase64(std::string const& _in);

}
} // namespace dev
8 changes: 8 additions & 0 deletions libp2p/ENR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Licensed under the GNU General Public License, Version 3.

#include "ENR.h"
#include <libdevcore/Base64.h>
#include <libdevcore/SHA3.h>

namespace dev
Expand Down Expand Up @@ -279,5 +280,12 @@ std::ostream& operator<<(std::ostream& _out, ENR const& _enr)
return _out;
}

std::string ENR::textEncoding() const
{
RLPStream s;
streamRLP(s);
return ("enr:" + toBase64URLSafe(ref(s.out())));
}

} // namespace p2p
} // namespace dev
2 changes: 2 additions & 0 deletions libp2p/ENR.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class ENR
ENR update(
std::map<std::string, bytes> const& _keyValuePair, SignFunction const& _signFunction) const;

std::string textEncoding() const;

private:
uint64_t m_seq = 0;
std::map<std::string, bytes> m_keyValuePairs;
Expand Down
14 changes: 11 additions & 3 deletions libp2p/Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,16 @@ class ReputationManager
struct NodeInfo
{
NodeInfo() = default;
NodeInfo(NodeID const& _id, std::string const& _address, unsigned _port, std::string const& _version):
id(_id), address(_address), port(_port), version(_version) {}
NodeInfo(NodeID const& _id, std::string const& _address, unsigned _port, std::string const& _version, std::string const& _enr):
id(_id), address(_address), port(_port), version(_version), enr(_enr) {}

std::string enode() const { return "enode://" + id.hex() + "@" + address + ":" + toString(port); }

NodeID id;
std::string address;
unsigned port;
std::string version;
std::string enr;
};

/**
Expand Down Expand Up @@ -240,7 +241,14 @@ class Host: public Worker
}

/// Get the node information.
p2p::NodeInfo nodeInfo() const { return NodeInfo(id(), (networkConfig().publicIPAddress.empty() ? m_tcpPublic.address().to_string() : networkConfig().publicIPAddress), m_tcpPublic.port(), m_clientVersion); }
p2p::NodeInfo nodeInfo() const
{
auto const e = enr();
return NodeInfo(id(),
(networkConfig().publicIPAddress.empty() ? m_tcpPublic.address().to_string() :
networkConfig().publicIPAddress),
m_tcpPublic.port(), m_clientVersion, e.textEncoding());
}

/// Get Ethereum Node Record of the host
ENR enr() const
Expand Down
2 changes: 2 additions & 0 deletions libweb3jsonrpc/AdminNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Json::Value AdminNet::admin_net_nodeInfo(std::string const& _session)
ret["listenAddr"] = i.address + ":" + toString(i.port);
ret["id"] = i.id.hex();
ret["enode"] = i.enode();
ret["enr"] = i.enr;
return ret;
}

Expand All @@ -51,6 +52,7 @@ Json::Value AdminNet::admin_nodeInfo()
ret["listenAddr"] = i.address + ":" + toString(i.port);
ret["id"] = i.id.hex();
ret["enode"] = i.enode();
ret["enr"] = i.enr;
ret["protocols"] = Json::objectValue;
ret["protocols"]["eth"] = Json::objectValue; //@todo fill with information
return ret;
Expand Down
4 changes: 4 additions & 0 deletions test/unittests/libp2p/ENRTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ TEST(enr, parse)
"/oxVtw0RW/QAdpzBQA8yWM0xOIN1ZHCCdl8=");
ENR enr = IdentitySchemeV4::parseENR(RLP{rlp});

EXPECT_EQ(enr.textEncoding(),
"enr:-"
"IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5w"
"BgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8");
EXPECT_EQ(enr.signature(),
fromHex("7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f3"
"0813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c"));
Expand Down