Skip to content
Open
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
41 changes: 41 additions & 0 deletions src/OfflineTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <RippleKey.h>
#include <Serialize.h>

#include <ripple/basics/Slice.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/beast/core/SemanticVersion.h>
#include <ripple/beast/unit_test.h>
#include <ripple/protocol/BuildInfo.h>
Expand Down Expand Up @@ -285,6 +287,36 @@ doCreateKeyfile(
return EXIT_SUCCESS;
}

int
doPublicKey(std::string const& publicKeyHex)
{
auto const error = [&publicKeyHex]() -> boost::optional<char const*> {
using namespace ripple;
if (auto blob = strUnHex(publicKeyHex))
Comment on lines +293 to +295
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doPublicKey introduces boost::optional just to carry an error message, while the rest of this file primarily uses std::optional. Consider switching this to std::optional<std::string> (or similar) and returning owned strings instead of char const* to avoid mixing optional types and to keep error handling consistent.

Copilot uses AI. Check for mistakes.
{
auto const slice = makeSlice(*blob);
if (!publicKeyType(slice))
return "Bad public key format.";
PublicKey const publicKey(slice);
auto const idSigner = calcAccountID(publicKey);
std::cout << "Public key: " << publicKey
<< "\nAccount ID: " << idSigner << std::endl;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doPublicKey prints the derived AccountID via the stream operator (<< idSigner). Elsewhere in this codebase, AccountID is consistently rendered using toBase58(calcAccountID(...)) (e.g., doCreateKeyfile and keyfile JSON). To keep the CLI output consistent and ensure the command returns a classic r... account string, format the account with toBase58(idSigner) (or to_string(idSigner) if that is the established base58 helper) instead of relying on operator<<.

Suggested change
<< "\nAccount ID: " << idSigner << std::endl;
<< "\nAccount ID: " << toBase58(idSigner) << std::endl;

Copilot uses AI. Check for mistakes.
return {};
}
else
{
return "Invalid hex";
}
}();
if (error)
{
std::cerr << "Invalid public key " << publicKeyHex << " " << *error
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

std::string
getStdin()
{
Expand Down Expand Up @@ -347,6 +379,10 @@ runCommand(
auto const argumenterror = []() {
throw std::runtime_error("Syntax error: Wrong number of arguments");
};
auto const publickey =
[](auto const& publicKeyHex, auto const&, auto const&) {
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publickey command action dereferences *publicKeyHex without a BOOST_ASSERT(publicKeyHex) like the other input-required commands (serialize, deserialize, sign, etc.). Even though runCommand should enforce the invariant, adding the assert keeps behavior consistent and avoids undefined behavior if the input dispatch changes later.

Suggested change
[](auto const& publicKeyHex, auto const&, auto const&) {
[](auto const& publicKeyHex, auto const&, auto const&) {
BOOST_ASSERT(publicKeyHex);

Copilot uses AI. Check for mistakes.
return doPublicKey(*publicKeyHex);
};
static map<string, commandParams> const commandArgs = {
{"serialize", {false, serialize}},
{"deserialize", {false, deserialize}},
Expand All @@ -355,6 +391,7 @@ runCommand(
{"asign", {false, asign}},
{"txhash", {false, txhash}},
{"createkeyfile", {true, createkeyfile}},
{"publickey", {false, publickey}},
};

auto const iArgs = commandArgs.find(command);
Expand Down Expand Up @@ -428,6 +465,10 @@ printHelp(
createkeyfile [<key>|--stdin] Create keyfile. A random
seed will be used if no <key> is provided on the command line
or from standard input using --stdin.
Miscellaneous:
publickey <hex public key> Get the account id from
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The help text for publickey doesn't mention that --stdin is also accepted (since runCommand supports InputType::readstdin for commands with allowNoInput == false). Either document publickey <hex public key>|--stdin like the other commands, or explicitly reject --stdin for this command if it's not intended.

Suggested change
publickey <hex public key> Get the account id from
publickey <hex public key>|--stdin Get the account id from

Copilot uses AI. Check for mistakes.
a public key.


Default keyfile is: )"
<< defaultKeyfile << "\n";
Expand Down
30 changes: 30 additions & 0 deletions src/test/OfflineTool_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,35 @@ class OfflineTool_test : public beast::unit_test::suite
}
}

void
testPublicKey()
{
testcase("Get AccountID from Public Key");

std::string const pkHex{
"036F382B723879499B6067B00B241DDF6FBA7599E9F6BF36A422150CEE75FF08F"
"8"};
std::string const account{"rGse36vmL3teKPJwHvKaqgxKkrMKEbATGN"};

auto const [out, err] = [&pkHex, this]() {
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the lambda in testPublicKey captures this but doesn't use it. Dropping the unused capture avoids warnings under stricter compiler flags.

Suggested change
auto const [out, err] = [&pkHex, this]() {
auto const [out, err] = [&pkHex]() {

Copilot uses AI. Check for mistakes.
CoutRedirect coutRedirect;

std::vector<std::string> args;
args.push_back(pkHex);

auto const exit =
runCommand("publickey", args, {}, {}, InputType::commandline);
BEAST_EXPECT(exit == EXIT_SUCCESS);
return std::make_pair(coutRedirect.out(), coutRedirect.err());
}();

std::string const expected =
"Public key: " + pkHex + "\nAccount ID: " + account + "\n";

BEAST_EXPECTS(err.empty(), err);
BEAST_EXPECTS(out == expected, out);
}
Comment on lines +628 to +655
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testPublicKey doesn't currently exercise the failure paths added in doPublicKey (invalid hex and invalid public-key bytes). Adding negative tests here would protect the new error handling and output formatting from regressions.

Copilot uses AI. Check for mistakes.

void
testRunCommand()
{
Expand Down Expand Up @@ -717,6 +746,7 @@ class OfflineTool_test : public beast::unit_test::suite
testSingleSign();
testMultiSign();
testCreateKeyfile();
testPublicKey();
testRunCommand();
}
};
Expand Down
Loading