aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMonzero Build System <builds@monzero.org>2026-08-15 21:55:20 +0100
committerMonzero Build System <builds@monzero.org>2026-08-15 21:55:20 +0100
commite933bd36cee44b42d631c1c64e9f3df027be7ab0 (patch)
tree0a35af5b088d2226a693cfee82dd12b5a813b31f /tests
parentfb59a510e4c61e9b971c5197856144fda7b6ec7a (diff)
downloadmonzero-core-e933bd36cee44b42d631c1c64e9f3df027be7ab0.tar.gz
monzero-core-e933bd36cee44b42d631c1c64e9f3df027be7ab0.tar.xz
monzero-core-e933bd36cee44b42d631c1c64e9f3df027be7ab0.zip
Add strict canonical asset descriptor decoding
Diffstat (limited to 'tests')
-rw-r--r--tests/unit_tests/asset_types.cpp62
1 files changed, 62 insertions, 0 deletions
diff --git a/tests/unit_tests/asset_types.cpp b/tests/unit_tests/asset_types.cpp
index b2f250fc5..79f26cd29 100644
--- a/tests/unit_tests/asset_types.cpp
+++ b/tests/unit_tests/asset_types.cpp
@@ -55,6 +55,68 @@ TEST(asset_types, deterministic_canonical_identity)
ASSERT_GT(encoded.size(), descriptor.metadata_reference.size());
}
+TEST(asset_types, canonical_descriptor_round_trip)
+{
+ for (const auto network : {cryptonote::MAINNET, cryptonote::TESTNET, cryptonote::STAGENET})
+ {
+ const auto original = make_descriptor(network);
+ std::vector<uint8_t> encoded;
+ ASSERT_TRUE(cryptonote::assets::encode_issuance_descriptor(original, encoded));
+
+ cryptonote::assets::issuance_descriptor decoded;
+ ASSERT_TRUE(cryptonote::assets::decode_issuance_descriptor(encoded, decoded));
+ EXPECT_EQ(original.version, decoded.version);
+ EXPECT_EQ(original.network, decoded.network);
+ EXPECT_EQ(original.type, decoded.type);
+ EXPECT_EQ(original.issuer_key, decoded.issuer_key);
+ EXPECT_EQ(original.issuance_nonce, decoded.issuance_nonce);
+ EXPECT_EQ(original.atomic_supply, decoded.atomic_supply);
+ EXPECT_EQ(original.display_decimals, decoded.display_decimals);
+ EXPECT_EQ(original.metadata_hash, decoded.metadata_hash);
+ EXPECT_EQ(original.collection_id, decoded.collection_id);
+ EXPECT_EQ(original.metadata_reference, decoded.metadata_reference);
+
+ std::vector<uint8_t> reencoded;
+ ASSERT_TRUE(cryptonote::assets::encode_issuance_descriptor(decoded, reencoded));
+ EXPECT_EQ(encoded, reencoded);
+ }
+}
+
+TEST(asset_types, descriptor_decoder_rejects_truncation_and_noncanonical_lengths)
+{
+ std::vector<uint8_t> encoded;
+ ASSERT_TRUE(cryptonote::assets::encode_issuance_descriptor(
+ make_descriptor(cryptonote::TESTNET), encoded));
+
+ cryptonote::assets::issuance_descriptor decoded;
+ std::string error;
+ for (size_t size = 0; size < encoded.size(); ++size)
+ {
+ const std::vector<uint8_t> truncated(encoded.begin(), encoded.begin() + size);
+ EXPECT_FALSE(cryptonote::assets::decode_issuance_descriptor(truncated, decoded, &error))
+ << "accepted truncated size " << size;
+ }
+
+ auto trailing = encoded;
+ trailing.push_back(0);
+ EXPECT_FALSE(cryptonote::assets::decode_issuance_descriptor(trailing, decoded, &error));
+
+ auto bad_domain = encoded;
+ bad_domain[0] ^= 1;
+ EXPECT_FALSE(cryptonote::assets::decode_issuance_descriptor(bad_domain, decoded, &error));
+
+ auto bad_version = encoded;
+ bad_version[sizeof("MonzeroAssetIssuanceV2") - 1]++;
+ EXPECT_FALSE(cryptonote::assets::decode_issuance_descriptor(bad_version, decoded, &error));
+
+ // The final two bytes before the reference are its little-endian length.
+ const size_t length_offset = encoded.size() - make_descriptor(cryptonote::TESTNET).metadata_reference.size() - 2;
+ auto oversized = encoded;
+ oversized[length_offset] = 1;
+ oversized[length_offset + 1] = 1;
+ EXPECT_FALSE(cryptonote::assets::decode_issuance_descriptor(oversized, decoded, &error));
+}
+
TEST(asset_types, network_domain_separation)
{
auto mainnet = make_descriptor(cryptonote::MAINNET);