diff --git a/docs/software/commands.md b/docs/software/commands.md index e978cb9ee0..1ec3f9f006 100644 --- a/docs/software/commands.md +++ b/docs/software/commands.md @@ -34,9 +34,9 @@ forcescp doesn't change the requirements for quorum so although this node will e * **--metric METRIC**: Report metric METRIC on exit. Used for gathering a metric cumulatively during a test run. * **--newdb**: Clears the local database and resets it to the genesis ledger. If you connect to the network after that it will catch up from scratch. * **--newhist ARCH**: Initialize the named history archive ARCH. ARCH should be one of the history archives you have specified in the stellar-core.cfg. This will write a `.well-known/stellar-history.json` file in the archive root. -* **--printtxn FILE**: Pretty-print a binary file containing a - `TransactionEnvelope`. If FILE is "-", the transaction is read from +* **--printxdr FILE**: Pretty-print a binary file containing an XDR object. If FILE is "-", the XDR object is read from standard input. +* **--filetype [auto|ledgerheader|meta|result|resultpair|tx|txfee]**: toggle for type used for printxdr (default: auto). * **--signtxn FILE**: Add a digital signature to a transaction envelope stored in binary format in FILE, and send the result to standard output (which should be redirected to a file or piped diff --git a/src/main/dumpxdr.cpp b/src/main/dumpxdr.cpp index 91a8055328..e23e6f675d 100644 --- a/src/main/dumpxdr.cpp +++ b/src/main/dumpxdr.cpp @@ -5,6 +5,7 @@ #include "util/Fs.h" #include "util/XDROperators.h" #include "util/XDRStream.h" +#include "util/format.h" #include #include #include @@ -27,6 +28,8 @@ extern "C" { #define isatty _isatty #endif // MSVC +using namespace std::placeholders; + namespace stellar { @@ -50,7 +53,7 @@ dumpstream(XDRInputFileStream& in) } void -dumpxdr(std::string const& filename) +dumpXdrStream(std::string const& filename) { std::regex rx( ".*(ledger|bucket|transactions|results|scp)-[[:xdigit:]]+\\.xdr"); @@ -117,19 +120,73 @@ readFile(const std::string& filename, bool base64 = false) return {ret.begin(), ret.end()}; } +template +void +printOneXdr(xdr::opaque_vec<> const& o, std::string const& desc) +{ + T tmp; + xdr::xdr_from_opaque(o, tmp); + std::cout << xdr::xdr_to_string(tmp, desc.c_str()) << std::endl; +} + void -printtxn(const std::string& filename, bool base64) +printXdr(std::string const& filename, std::string const& filetype, bool base64) { +// need to use this pattern as there is no good way to get a human readable +// type name from a type +#define PRINTONEXDR(T) std::bind(printOneXdr, _1, #T) + auto dumpMap = + std::map const&)>>{ + {"ledgerheader", PRINTONEXDR(LedgerHeader)}, + {"meta", PRINTONEXDR(TransactionMeta)}, + {"result", PRINTONEXDR(TransactionResult)}, + {"resultpair", PRINTONEXDR(TransactionResultPair)}, + {"tx", PRINTONEXDR(TransactionEnvelope)}, + {"txfee", PRINTONEXDR(LedgerEntryChanges)}}; +#undef PRINTONEXDR + try { - using xdr::operator<<; - TransactionEnvelope txenv; - xdr::xdr_from_opaque(readFile(filename, base64), txenv); - std::cout << txenv; + auto d = readFile(filename, base64); + + if (filetype == "auto") + { + bool processed = false; + for (auto const& it : dumpMap) + { + try + { + it.second(d); + processed = true; + break; + } + catch (xdr::xdr_runtime_error) + { + } + } + if (!processed) + { + throw std::invalid_argument("Could not detect type"); + } + } + else + { + auto it = dumpMap.find(filetype); + if (it != dumpMap.end()) + { + it->second(d); + } + else + { + throw std::invalid_argument( + fmt::format("unknown filetype {}", filetype)); + } + } } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; + std::cerr << "Could not decode with type '" << filetype + << "' : " << e.what() << std::endl; } } diff --git a/src/main/dumpxdr.h b/src/main/dumpxdr.h index 70b815c317..bc756efc8a 100644 --- a/src/main/dumpxdr.h +++ b/src/main/dumpxdr.h @@ -10,8 +10,9 @@ namespace stellar { extern const char* signtxn_network_id; -void dumpxdr(std::string const& filename); -void printtxn(std::string const& filename, bool base64); +void dumpXdrStream(std::string const& filename); +void printXdr(std::string const& filename, std::string const& filetype, + bool base64); void signtxn(std::string const& filename, bool base64); void priv2pub(); } diff --git a/src/main/main.cpp b/src/main/main.cpp index 559890187e..8c3d0b8afb 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -71,11 +71,12 @@ enum opttag OPT_METRIC, OPT_NEWDB, OPT_NEWHIST, - OPT_PRINTTXN, + OPT_PRINTXDR, OPT_SEC2PUB, OPT_SIGNTXN, OPT_NETID, OPT_TEST, + OPT_FILETYPE, OPT_VERSION }; @@ -90,7 +91,8 @@ static const struct option stellar_core_options[] = { {"checkquorum", optional_argument, nullptr, OPT_CHECKQUORUM}, {"base64", no_argument, nullptr, OPT_BASE64}, {"dumpxdr", required_argument, nullptr, OPT_DUMPXDR}, - {"printtxn", required_argument, nullptr, OPT_PRINTTXN}, + {"printxdr", required_argument, nullptr, OPT_PRINTXDR}, + {"filetype", required_argument, nullptr, OPT_FILETYPE}, {"signtxn", required_argument, nullptr, OPT_SIGNTXN}, {"netid", required_argument, nullptr, OPT_NETID}, {"loadxdr", required_argument, nullptr, OPT_LOADXDR}, @@ -131,16 +133,14 @@ usage(int err = 1) " Use current as SEQ to catchup to " "'current' history checkpoint\n" " --c Send a command to local stellar-core. " - "try " - "'--c help' for more information\n" + "try '--c help' for more information\n" " --conf FILE Specify a config file ('-' for STDIN, " "default 'stellar-core.cfg')\n" " --convertid ID Displays ID in all known forms\n" " --dumpxdr FILE Dump an XDR file, for debugging\n" " --loadxdr FILE Load an XDR bucket file, for testing\n" " --forcescp Next time stellar-core is run, SCP will " - "start " - "with the local ledger rather than waiting to hear from the " + "start with the local ledger rather than waiting to hear from the " "network.\n" " --fuzz FILE Run a single fuzz input and exit\n" " --genfuzz FILE Generate a random fuzzer input file\n" @@ -155,19 +155,19 @@ usage(int err = 1) " --offlineinfo Return information for an offline " "instance\n" " --ll LEVEL Set the log level. (redundant with --c " - "ll " - "but " - "you need this form for the tests.)\n" + "ll but you need this form for the tests.)\n" " LEVEL can be: trace, debug, info, error, " "fatal\n" " --metric METRIC Report metric METRIC on exit\n" " --newdb Creates or restores the DB to the " - "genesis " - "ledger\n" + "genesis ledger\n" " --newhist ARCH Initialize the named history archive " "ARCH\n" - " --printtxn FILE Pretty-print one transaction envelope," - " then quit\n" + " --printxdr FILE Pretty print XDR content from FILE, " + "then quit\n" + " --filetype " + "[auto|ledgerheader|meta|result|resultpair|tx|txfee] toggle for type " + "used for printxdr\n" " --report-last-history-checkpoint\n" " Report information about last checkpoint " "available in history archives\n" @@ -718,6 +718,7 @@ main(int argc, char* const* argv) std::string loadXdrBucket; std::vector newHistories; std::vector metrics; + string filetype = "auto"; int opt; while ((opt = getopt_long_only(argc, argv, "c:", stellar_core_options, @@ -756,11 +757,14 @@ main(int argc, char* const* argv) StrKeyUtils::logKey(std::cout, std::string(optarg)); return 0; case OPT_DUMPXDR: - dumpxdr(std::string(optarg)); + dumpXdrStream(std::string(optarg)); return 0; - case OPT_PRINTTXN: - printtxn(std::string(optarg), base64); + case OPT_PRINTXDR: + printXdr(std::string(optarg), filetype, base64); return 0; + case OPT_FILETYPE: + filetype = std::string(optarg); + break; case OPT_SIGNTXN: signtxn(std::string(optarg), base64); return 0;