Skip to content

Add JsonInputArchive overrides to XDRCereal#5130

Open
drebelsky wants to merge 2 commits intostellar:masterfrom
drebelsky:add-cereal-overrides
Open

Add JsonInputArchive overrides to XDRCereal#5130
drebelsky wants to merge 2 commits intostellar:masterfrom
drebelsky:add-cereal-overrides

Conversation

@drebelsky
Copy link
Contributor

@drebelsky drebelsky commented Feb 10, 2026

Resolves #5041. Note that the overrides are intentionally hidden behind BUILD_TESTS because we shouldn't use the input overrides on production code (we should store XDR as XDR, not our custom JSON overrides that break every so often). The overloads also don't get used anywhere else, but I think it's probably still worth having them + the tests in the repo, so we can quickly write an ad-hoc tool to parse core JSON if we need to again.

Testing notes
The tests right now are written to check that we can roundtrip 1000 random values of most of our XDR types. Unfortunately, due to the heavy template instantiation, compilation takes ~1 minute on my laptop. With the current configurable values (1000 random values per type, use 1 for levels for xdr::generator_t, limit the autocheck::arbitrary to generating things of at most size 10), the tests take about a minute to run. For reference, 1000 random values for type, limiting autocheck::arbitrary to 5, and using the xdrpp autocheck::generator override took ~17 seconds. Limiting the nesting depth is probably fine since we're checking the nested structures.

Alternatively, we could try roundtripping (by hand or generation) a subset of the particular overloads. This has the benefit of compiling faster. However, it also requires us to actively keep the tests up-to-date (the class list can be updated more intermittently, especially since including things like BucketEntry help gives provide coverage for future types).

There's also a basic set of unit tests that check that the overrides get called.

@drebelsky drebelsky force-pushed the add-cereal-overrides branch from ab727fc to 92f99fb Compare February 10, 2026 19:09
@drebelsky drebelsky marked this pull request as ready for review March 3, 2026 18:45
Copilot AI review requested due to automatic review settings March 3, 2026 18:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

Comment on lines +401 to +405
auto setAlpha = [&assetCode, &issuer](auto& alpha) {
alpha.assetCode.fill(0);
std::copy(assetCode.begin(), assetCode.end(), alpha.assetCode.begin());
alpha.issuer = issuer;
};
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

In the JSONInputArchive Asset override, assetCode read from the "assetCode" string is not length-checked before copying into the fixed-size opaque_array in setAlpha(...). If the JSON contains a long string, std::copy(assetCode.begin(), assetCode.end(), alpha.assetCode.begin()) will write past the end of the destination array (UB). Validate assetCode.size() (<= 4 or <= 12 as appropriate) before copying, and throw/fail cleanly when it's out of range.

Copilot uses AI. Check for mistakes.
Comment on lines +283 to +288
std::string hex;
xdr::archive(ar, hex, field);
auto bin = stellar::hexToBin(hex);
releaseAssertOrThrow(bin.size() == N);
std::copy(bin.begin(), bin.end(), s.begin());
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The new JSONInputArchive overrides use releaseAssertOrThrow(...), but XDRCereal.h doesn't include util/GlobalChecks.h where it's defined. Add the include (ideally within the BUILD_TESTS block) so test builds don't depend on transitive includes.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,684 @@
#include "crypto/StrKey.h"
#include "test/Catch2.h"
#include "util/Decoder.h"
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This test file uses releaseAssert(...) in helpers but doesn't include util/GlobalChecks.h where it is defined. Add the missing include to avoid compilation failures that depend on transitive includes.

Suggested change
#include "util/Decoder.h"
#include "util/Decoder.h"
#include "util/GlobalChecks.h"
Copilot uses AI. Check for mistakes.
Comment on lines +1 to +4
#include "crypto/StrKey.h"
#include "test/Catch2.h"
#include "util/Decoder.h"
#include <fmt/format.h>
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

<fmt/format.h> and crypto/StrKey.h appear unused in this test file; removing them will reduce compile time and avoid unused-include churn.

Suggested change
#include "crypto/StrKey.h"
#include "test/Catch2.h"
#include "util/Decoder.h"
#include <fmt/format.h>
#include "test/Catch2.h"
#include "util/Decoder.h"
Copilot uses AI. Check for mistakes.
#include "transactions/TransactionUtils.h"
#include "util/types.h"
#include <cereal/archives/json.hpp>
#include <string>
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The new JSONInputArchive enum override uses std::unordered_map but XDRCereal.h doesn't include <unordered_map> (and it also uses std::back_inserter without including ). Add the missing standard headers (and keep them within the BUILD_TESTS guard if you want to limit production impact) to avoid non-deterministic builds relying on transitive includes.

Suggested change
#include <string>
#include <string>
#include <unordered_map>
#include <iterator>
Copilot uses AI. Check for mistakes.
Comment on lines +173 to +178
if (std::is_same_v<std::decay<decltype(assetCode)>,
stellar::AssetCode12> &&
first0 <= 4)
{
valid = false;
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The ASSET_CODE_12 validity check uses std::decay<decltype(assetCode)> instead of std::decay_t<...> (or typename std::decay<...>::type). As written, the condition is effectively never true, so the first0 <= 4 rule for AssetCode12 won't be enforced and invalid codes may serialize as strings instead of raw bytes.

Copilot uses AI. Check for mistakes.
xdr::archive(ar, assetCode, "assetCodeRaw");
}
};
std::string code;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

std::string code; is now unused after switching to the archive(...) lambda. Please remove it (or use it) to avoid unused-variable warnings (which may be treated as errors in some builds).

Suggested change
std::string code;
Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants