diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index a431b5562d3..27dba963422 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ #include #include +#include #include #include #include @@ -3101,7 +3103,12 @@ NetworkOPsImp::transJson( transResultInfo(result, sToken, sHuman); jvObj[jss::type] = "transaction"; - jvObj[jss::transaction] = transaction->getJson(JsonOptions::none); + // NOTE jvObj which is not a finished object for either API version. After + // it's populated, we need to finish it for a specific API version. This is + // done in a loop, near the end of this function. + std::string hash = {}; + jvObj[jss::transaction] = + transaction->getJson(JsonOptions::none, false, {std::ref(hash)}); if (meta) { @@ -3165,11 +3172,21 @@ NetworkOPsImp::transJson( assert(index < MultiApiJson::size); if (index != lastIndex) { + Json::Value& jvTx = multiObj.val[index]; RPC::insertDeliverMax( - multiObj.val[index][jss::transaction], - transaction->getTxnType(), - apiVersion); + jvTx[jss::transaction], transaction->getTxnType(), apiVersion); lastIndex = index; + + if (apiVersion > 1) + { + jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction); + jvTx[jss::hash] = hash; + // TODO set `jvObj[jss::close_time_iso]` if validated + } + else + { + jvTx[jss::transaction][jss::hash] = hash; + } } } diff --git a/src/ripple/protocol/STTx.h b/src/ripple/protocol/STTx.h index c6a9e053c3d..195f3a1de3f 100644 --- a/src/ripple/protocol/STTx.h +++ b/src/ripple/protocol/STTx.h @@ -108,8 +108,16 @@ class STTx final : public STObject, public CountedObject Json::Value getJson(JsonOptions options) const override; + + /// If `hash` is set, will store hash inside the provided string. Otherwise + /// hash will be stored as nested jss::hash element inside the returned JSON + /// Additionally, if `hash` is set and `binary` is true, will not create + /// nested jss::tx for binary hex; instead will return it as JSON string Json::Value - getJson(JsonOptions options, bool binary) const; + getJson( + JsonOptions options, + bool binary, + std::optional> hash = {}) const; void sign(PublicKey const& publicKey, SecretKey const& secretKey); diff --git a/src/ripple/protocol/impl/STTx.cpp b/src/ripple/protocol/impl/STTx.cpp index 1ce4ddb64b7..abcd01049b0 100644 --- a/src/ripple/protocol/impl/STTx.cpp +++ b/src/ripple/protocol/impl/STTx.cpp @@ -234,17 +234,33 @@ Json::Value STTx::getJson(JsonOptions) const } Json::Value -STTx::getJson(JsonOptions options, bool binary) const +STTx::getJson( + JsonOptions options, + bool binary, + std::optional> hash) const { + if (!hash) // Old behaviour - default because `hash = {}` in declaration + { + if (binary) + { + Json::Value ret; + Serializer s = STObject::getSerializer(); + ret[jss::tx] = strHex(s.peekData()); + ret[jss::hash] = to_string(getTransactionID()); + return ret; + } + return getJson(options); + } + + // Since `hash` is set, do not populate `hash` inside JSON output + hash->get() = to_string(getTransactionID()); if (binary) { - Json::Value ret; Serializer s = STObject::getSerializer(); - ret[jss::tx] = strHex(s.peekData()); - ret[jss::hash] = to_string(getTransactionID()); + Json::Value ret = strHex(s.peekData()); return ret; } - return getJson(options); + return STObject::getJson(JsonOptions::none); // Yes, want `none` } std::string const&