Skip to content

Commit

Permalink
Add --json flag to dump-xdr subcommand, implement via cereal
Browse files Browse the repository at this point in the history
  • Loading branch information
graydon committed Feb 11, 2020
1 parent 92d7da9 commit 04d05bd
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 12 deletions.
6 changes: 4 additions & 2 deletions src/main/CommandLine.cpp
Expand Up @@ -629,9 +629,11 @@ int
runDumpXDR(CommandLineArgs const& args)
{
std::string xdr;
bool json = false;
auto jsonOption = clara::Opt{json}["--json"]("dump json");

return runWithHelp(args, {fileNameParser(xdr)}, [&] {
dumpXdrStream(xdr);
return runWithHelp(args, {jsonOption, fileNameParser(xdr)}, [&] {
dumpXdrStream(xdr, json);
return 0;
});
}
Expand Down
106 changes: 97 additions & 9 deletions src/main/dumpxdr.cpp
@@ -1,11 +1,15 @@
#include "main/dumpxdr.h"
#include "crypto/Hex.h"
#include "crypto/SecretKey.h"
#include "transactions/SignatureUtils.h"
#include "util/Decoder.h"
#include "util/Fs.h"
#include "util/XDROperators.h"
#include "util/XDRStream.h"
#include "util/format.h"
#include "util/types.h"
#include <cereal/archives/json.hpp>
#include <cereal/cereal.hpp>
#include <iostream>
#include <regex>
#include <xdrpp/printer.h>
Expand All @@ -30,6 +34,78 @@ extern "C" {

using namespace std::placeholders;

template <uint32_t N>
void
cereal_override(cereal::JSONOutputArchive& ar, const xdr::opaque_array<N>& s,
const char* field)
{
xdr::archive(ar, stellar::binToHex(stellar::ByteSlice(s.data(), s.size())),
field);
}

// We still need one explicit composite-container override because cereal
// appears to process arrays-of-arrays internally, without calling back through
// an NVP adaptor.
template <uint32_t N>
void
cereal_override(cereal::JSONOutputArchive& ar,
const xdr::xarray<stellar::Hash, N>& s, const char* field)
{
std::vector<std::string> tmp;
for (auto const& h : s)
{
tmp.emplace_back(
stellar::binToHex(stellar::ByteSlice(h.data(), h.size())));
}
xdr::archive(ar, tmp, field);
}

template <uint32_t N>
void
cereal_override(cereal::JSONOutputArchive& ar, const xdr::opaque_vec<N>& s,
const char* field)
{
xdr::archive(ar, stellar::binToHex(stellar::ByteSlice(s.data(), s.size())),
field);
}
void
cereal_override(cereal::JSONOutputArchive& ar, const stellar::PublicKey& s,
const char* field)
{
xdr::archive(ar, stellar::KeyUtils::toStrKey<stellar::PublicKey>(s), field);
}
void
cereal_override(cereal::JSONOutputArchive& ar, const stellar::Asset& s,
const char* field)
{
xdr::archive(ar, stellar::assetToString(s), field);
}

template <typename T>
void
cereal_override(cereal::JSONOutputArchive& ar, const xdr::pointer<T>& t,
const char* field)
{
// We tolerate a little information-loss here collapsing *T into T for
// the non-null case, and use JSON 'null' for the null case. This reads
// much better than the thing JSONOutputArchive does with PtrWrapper.
if (t)
{
xdr::archive(ar, *t, field);
}
else
{
ar.setNextName(field);
ar.writeName();
ar.saveValue(nullptr);
}
}

// This has to be included _after_ the cereal_override overloads above,
// otherwise some interplay of name lookup and visibility during the
// enable_if call in the cereal adaptor fails to find them.
#include <xdrpp/cereal.h>

namespace stellar
{

Expand All @@ -41,17 +117,29 @@ xdr_printer(const PublicKey& pk)

template <typename T>
void
dumpstream(XDRInputFileStream& in)
dumpstream(XDRInputFileStream& in, bool json)
{
T tmp;
while (in && in.readOne(tmp))
if (json)
{
std::cout << xdr::xdr_to_string(tmp) << std::endl;
cereal::JSONOutputArchive archive(std::cout);
archive.makeArray();
while (in && in.readOne(tmp))
{
archive(tmp);
}
}
else
{
while (in && in.readOne(tmp))
{
std::cout << xdr::xdr_to_string(tmp) << std::endl;
}
}
}

void
dumpXdrStream(std::string const& filename)
dumpXdrStream(std::string const& filename, bool json)
{
std::regex rx(
".*(ledger|bucket|transactions|results|scp)-[[:xdigit:]]+\\.xdr");
Expand All @@ -63,24 +151,24 @@ dumpXdrStream(std::string const& filename)

if (sm[1] == "ledger")
{
dumpstream<LedgerHeaderHistoryEntry>(in);
dumpstream<LedgerHeaderHistoryEntry>(in, json);
}
else if (sm[1] == "bucket")
{
dumpstream<BucketEntry>(in);
dumpstream<BucketEntry>(in, json);
}
else if (sm[1] == "transactions")
{
dumpstream<TransactionHistoryEntry>(in);
dumpstream<TransactionHistoryEntry>(in, json);
}
else if (sm[1] == "results")
{
dumpstream<TransactionHistoryResultEntry>(in);
dumpstream<TransactionHistoryResultEntry>(in, json);
}
else
{
assert(sm[1] == "scp");
dumpstream<SCPHistoryEntry>(in);
dumpstream<SCPHistoryEntry>(in, json);
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/main/dumpxdr.h
Expand Up @@ -9,7 +9,7 @@
namespace stellar
{

void dumpXdrStream(std::string const& filename);
void dumpXdrStream(std::string const& filename, bool json);
void printXdr(std::string const& filename, std::string const& filetype,
bool base64);
void signtxn(std::string const& filename, std::string netId, bool base64);
Expand Down

0 comments on commit 04d05bd

Please sign in to comment.