Skip to content

refactor: Always include encoding tag for KeyPackage and Welcome events#32

Merged
mubarakcoded merged 2 commits intomasterfrom
fix/encoding-tag-improvements
Dec 10, 2025
Merged

refactor: Always include encoding tag for KeyPackage and Welcome events#32
mubarakcoded merged 2 commits intomasterfrom
fix/encoding-tag-improvements

Conversation

@mubarakcoded
Copy link
Contributor

@mubarakcoded mubarakcoded commented Dec 5, 2025

  • Always include encoding tag (hex or base64) instead of only for base64
  • Revert to fixed-size tag array [Tag; 7] for KeyPackage events
  • Remove decode_key_package_content and decode_welcome_content wrappers
  • Inline decode_content calls directly at call sites
  • Remove redundant test comments and size comparison test
  • Remove decode tests that tested removed wrapper methods
  • Update tag count assertions in tests (6→7 for KeyPackage, 3→4 for Welcome)

Summary by CodeRabbit

  • Improvements

    • Encoding metadata is now always included in event and welcome tags; decoding is unified and logs the detected format.
  • Breaking Changes

    • Key-package creation now returns a fixed-size tag set (always including encoding) instead of a variable-length tag list.
  • Tests

    • Updated tests to expect new tag counts, ordering, encoding-tag presence/value, and consolidated decoding behavior; added encoding/decoding unit tests.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

Walkthrough

Encoding tags are now always included in welcome rumors and key-package events; create_key_package_for_event returns a fixed [Tag; 7]. Decoding was centralized to decode_content (now returns content and format), private decode helpers removed, and tests adjusted to the new tag layout and decoding flow.

Changes

Cohort / File(s) Summary
Unconditional encoding tag
crates/mdk-core/src/groups.rs, crates/mdk-core/src/welcomes.rs, crates/mdk-core/src/key_packages.rs
The encoding tag is emitted for all welcome rumors and key-package events (previously added only for Base64). Tests and tag-count expectations updated accordingly.
Key-package API & tag shape
crates/mdk-core/src/key_packages.rs
create_key_package_for_event return type changed from Result<(String, Vec<Tag>), Error> to Result<(String, [Tag; 7]), Error>. Tags are constructed as a fixed 7-element array with the encoding tag as the final element; tests updated for ordering and values.
Decoding centralization & helper removal
crates/mdk-core/src/welcomes.rs, crates/mdk-core/src/key_packages.rs
Removed private decoding helpers and unified callers to decode_content, which now returns (content, format); decoding format is logged. Failure paths standardized (e.g., ProcessedWelcome set to Failed) and parsing now uses the unified decode flow.
Tests added/adjusted
crates/mdk-core/src/util.rs, crates/mdk-core/src/welcomes.rs, crates/mdk-core/src/key_packages.rs
Added tests for encode/decode roundtrips and encoding extraction; updated or removed tests to reflect fixed tag layout and centralized decoding behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas needing extra attention:
    • All call-sites and consumers of create_key_package_for_event for the new fixed [Tag; 7] return type and tag ordering.
    • Any code assuming dynamic tag lengths or previous tag positions.
    • Decoding failure handling and ProcessedWelcome state transitions to ensure behavior remains correct after helper removal.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: making encoding tags unconditional for KeyPackage and Welcome events, which is the core objective across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/encoding-tag-improvements

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7427a6d and 519a716.

📒 Files selected for processing (1)
  • crates/mdk-core/src/util.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/mdk-core/src/util.rs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

❌ Coverage: 87.03% → 86.98% (-0.05%)

@mubarakcoded mubarakcoded requested review from dannym-arx and removed request for dannym-arx, erskingardner and jgmontoya December 5, 2025 01:23
@mubarakcoded mubarakcoded force-pushed the fix/encoding-tag-improvements branch from 25ff536 to 58210e8 Compare December 5, 2025 01:26
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/mdk-core/src/key_packages.rs (1)

24-41: Update doc comment to describe [Tag; 7] array instead of "Vec of tags"; fix .into() string conversions

The doc comment at lines 24-41 still describes the return as "A Vec of tags" but the function signature returns [Tag; 7]. Update the doc to specify the fixed array of 7 tags and document the guaranteed presence and order of the encoding tag at index 6.

All call sites (README.md, examples, tests, and test_util.rs) properly handle the [Tag; 7] return type.

Additionally, the encoding tag construction uses "encoding".into() at lines 94, 672, and 897. Per coding guidelines, prefer .to_string() or .to_owned() for &str to String conversion instead of .into().

🧹 Nitpick comments (2)
crates/mdk-core/src/welcomes.rs (1)

371-377: Update MIP‑02 test docs to reflect 4‑tag welcome structure

The tests now correctly assert 4 tags on welcome rumors (relays, event reference, client, encoding), but the test_welcome_event_structure_mip02_compliance doc comment still claims “exactly 3 tags”. Consider updating that comment (and any similar references) to avoid confusion between spec text and the enforced structure.

Also applies to: 425-430, 599-603, 695-696, 940-941

crates/mdk-core/src/key_packages.rs (1)

93-96: Minor style nit: prefer .to_string() over .into() for &strString

Per the Rust guidelines you’re following, consider switching "encoding".into() to "encoding".to_string() in the TagKind::Custom("encoding".into()) construction here (and the similar pattern in groups.rs) to keep &strString conversions consistent:

-            Tag::custom(
-                TagKind::Custom("encoding".into()),
-                [encoding.as_tag_value()],
-            ),
+            Tag::custom(
+                TagKind::Custom("encoding".to_string()),
+                [encoding.as_tag_value()],
+            ),

This is purely stylistic and doesn’t affect behavior.

Also applies to: 2109-2117, 2143-2151

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94792c1 and 25ff536.

📒 Files selected for processing (3)
  • crates/mdk-core/src/groups.rs (1 hunks)
  • crates/mdk-core/src/key_packages.rs (10 hunks)
  • crates/mdk-core/src/welcomes.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)

**/*.rs: All trait bounds should be written in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

Files:

  • crates/mdk-core/src/groups.rs
  • crates/mdk-core/src/key_packages.rs
  • crates/mdk-core/src/welcomes.rs
🧬 Code graph analysis (2)
crates/mdk-core/src/groups.rs (1)
crates/mdk-core/src/util.rs (1)
  • as_tag_value (62-67)
crates/mdk-core/src/welcomes.rs (1)
crates/mdk-core/src/util.rs (1)
  • decode_content (142-156)
🔇 Additional comments (2)
crates/mdk-core/src/groups.rs (1)

1291-1299: Welcome rumors now consistently carry an encoding tag

The added custom encoding tag, keyed off ContentEncoding and applied to every welcome rumor, is consistent with the new decoding flow and looks correct; no functional issues from this change.

crates/mdk-core/src/welcomes.rs (1)

294-301: Shared decode_content usage in preview_welcome looks correct

Switching to decode_content with explicit ContentEncoding and logging the decoded format integrates cleanly with the new encoding tag and preserves the existing error-path behavior (failed decodes recorded as ProcessedWelcome::Failed), so this change looks solid.

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

❌ Coverage: 87.03% → 86.98% (-0.05%)

@mubarakcoded mubarakcoded force-pushed the fix/encoding-tag-improvements branch from 58210e8 to bf3276f Compare December 5, 2025 01:31
@github-actions
Copy link

github-actions bot commented Dec 5, 2025

❌ Coverage: 87.03% → 86.98% (-0.05%)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
crates/mdk-core/src/welcomes.rs (1)

291-325: Centralized welcome decoding and format logging look solid

Using decode_content here with the extra debug log on the actual decoded format keeps welcome handling consistent with key-package decoding and makes failures persistently tracked via ProcessedWelcome::Failed. The duplicated failure-handling block shared with the later parse error path is fine, but could be factored into a small helper in the future if this pattern appears more often.

crates/mdk-core/src/key_packages.rs (2)

122-141: Unified key‑package decoding via decode_content is correct

parse_serialized_key_package now delegates to decode_content(key_package_str, encoding, "key package") and logs the decoded format, which matches the util contract and keeps base64/hex behavior centralized. Error mapping to Error::KeyPackage plus the updated tests for invalid encodings/inputs (test_invalid_key_package_parsing) ensure both formats fail fast with the right variant.

You might consider renaming the local format binding in the match to something like decoded_format to avoid shadowing the format! macro name and improve readability, but it’s not functionally problematic.

Also applies to: 950-971


2087-2117: Encoding‑tag tests for base64 and hex cover the new behavior well

The base64 and hex encoding tests now both ensure:

  • Content decodes under the expected encoding.
  • An "encoding" tag is present.
  • The second element of that tag is exactly "base64" or "hex".

Combined with the cross‑format compatibility test, this gives good coverage of the new always-present encoding tag behavior for key packages.

If you want slightly clearer intent, matching on tag.kind() == TagKind::Custom("encoding".into()) (like other tests do) instead of peeking at as_slice().first() would reduce reliance on the underlying slice layout, but the current assertions are still robust.

Also applies to: 2125-2151, 2153-2156, 2159-2212

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58210e8 and bf3276f.

📒 Files selected for processing (3)
  • crates/mdk-core/src/groups.rs (1 hunks)
  • crates/mdk-core/src/key_packages.rs (10 hunks)
  • crates/mdk-core/src/welcomes.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)

**/*.rs: All trait bounds should be written in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

Files:

  • crates/mdk-core/src/groups.rs
  • crates/mdk-core/src/welcomes.rs
  • crates/mdk-core/src/key_packages.rs
🧬 Code graph analysis (3)
crates/mdk-core/src/groups.rs (1)
crates/mdk-core/src/util.rs (1)
  • as_tag_value (62-67)
crates/mdk-core/src/welcomes.rs (1)
crates/mdk-core/src/util.rs (1)
  • decode_content (142-156)
crates/mdk-core/src/key_packages.rs (1)
crates/mdk-core/src/util.rs (1)
  • decode_content (142-156)
🔇 Additional comments (2)
crates/mdk-core/src/key_packages.rs (1)

20-41: Fixed 7‑tag key‑package API and encoding tag ordering are consistent

The switch to Result<(String, [Tag; 7]), Error> plus the literal 7‑element array makes the tag schema explicit and compile‑time enforced. The documented tag order matches the array construction, and the updated tests (test_key_package_creation_and_parsing, test_complete_tag_structure_mip00_compliance) correctly assert both the total length and that the 7th tag is the custom "encoding" tag. This aligns nicely with the always-present encoding tag requirement across the codebase.

Also applies to: 48-53, 86-99, 665-673, 861-863, 895-899

crates/mdk-core/src/groups.rs (1)

1272-1299: Always including the welcome encoding tag is correct and consistent

Building welcome rumors with a fixed 4‑tag structure (relays, event ref, client, encoding) aligns welcomes with key‑package events and with the updated tests/spec expectations. Using the same "encoding" custom tag populated from ContentEncoding::as_tag_value() ensures ContentEncoding::from_tags can reliably recover the format for both legacy (no tag) and new events.

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

❌ Coverage: 87.03% → 87.02% (-0.01%)

@mubarakcoded mubarakcoded force-pushed the fix/encoding-tag-improvements branch from 7800ad4 to 9dc8f16 Compare December 7, 2025 02:34
@github-actions
Copy link

github-actions bot commented Dec 7, 2025

⚠️ Coverage: 87.03% → 87.03% (0.00%)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/mdk-core/src/welcomes.rs (1)

371-377: Update comment to reflect 4-tag welcome structure

The test assertion at line 425 correctly checks welcome_rumor.tags.len() == 4, but the comment at line 371 states "exactly 3 tags (relays + event reference + client)". Update this comment to "exactly 4 tags (relays + event reference + client + encoding)" to match the actual test requirements.

🧹 Nitpick comments (4)
crates/mdk-core/src/util.rs (1)

212-228: Move nostr::Tag import out of the test function

use nostr::Tag; inside test_from_tags_returns_encoding violates the “no inner use” guideline; please move this import to the top of the tests module instead.

As per coding guidelines, all use statements should live at the top of the file/module.

crates/mdk-core/src/welcomes.rs (1)

291-324: Centralized welcome decoding via decode_content looks correct; consider simplifying error formatting

Using ContentEncoding::from_tags and decode_content to drive decoding (with a hex default) is consistent with the new encoding‑tag design, and logging the decoded format is helpful. In the error branch, you can drop the debug formatter and just use {} for e to avoid quoting the already‑formatted error string:

- let error_string = format!(
-     "Error decoding welcome event content ({}): {:?}",
-     encoding.as_tag_value(),
-     e
- );
+ let error_string = format!(
+     "Error decoding welcome event content ({}): {}",
+     encoding.as_tag_value(),
+     e
+ );
crates/mdk-core/src/key_packages.rs (2)

24-41: Encoding/tag handling in key‑package creation/parsing looks correct; align "encoding" conversions with style guide

The refactored create_key_package_for_event correctly:

  • Picks ContentEncoding from use_base64_encoding,
  • Uses shared encode_content,
  • Returns a fixed [Tag; 7] including a trailing encoding tag, and
  • Leaves parse_key_package free to derive the format via ContentEncoding::from_tags.

parse_serialized_key_package’s use of decode_content(..., "key package") and the format debug log are also consistent with the new util API and error expectations.

To match the “prefer .to_string() over .into()” guideline for &str → String, consider updating the custom kind construction (and matching test) like this:

- Tag::custom(
-     TagKind::Custom("encoding".into()),
-     [encoding.as_tag_value()],
- ),
+ Tag::custom(
+     TagKind::Custom("encoding".to_string()),
+     [encoding.as_tag_value()],
+ ),

and

- assert_eq!(tags[6].kind(), TagKind::Custom("encoding".into()));
+ assert_eq!(tags[6].kind(), TagKind::Custom("encoding".to_string()));

As per coding guidelines, .to_string() is preferred here.

Also applies to: 48-52, 72-85, 86-97, 127-133


2087-2117: Base64 and hex encoding tests validate both content and encoding tag; minor optional cleanup

The new test_key_package_base64_encoding and test_key_package_hex_encoding correctly:

  • Exercise both encoding modes via MdkConfig::use_base64_encoding,
  • Verify that content decodes as base64/hex, and
  • Assert that the ["encoding", "..."] tag is present with the expected value.

If you want to trim a tiny allocation in the tag lookup, you could compare against "encoding" as &str instead of constructing a String each time:

- .find(|t| t.as_slice().first() == Some(&"encoding".to_string()));
+ .find(|t| t.as_slice().first().map(String::as_str) == Some("encoding"));

Also applies to: 2125-2151

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf3276f and 9dc8f16.

📒 Files selected for processing (4)
  • crates/mdk-core/src/groups.rs (1 hunks)
  • crates/mdk-core/src/key_packages.rs (10 hunks)
  • crates/mdk-core/src/util.rs (1 hunks)
  • crates/mdk-core/src/welcomes.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/mdk-core/src/groups.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)

**/*.rs: All trait bounds should be written in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

Files:

  • crates/mdk-core/src/util.rs
  • crates/mdk-core/src/key_packages.rs
  • crates/mdk-core/src/welcomes.rs
🧠 Learnings (1)
📚 Learning: 2025-12-03T10:18:10.432Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/rust.mdc:0-0
Timestamp: 2025-12-03T10:18:10.432Z
Learning: Applies to **/*.rs : Use inline `mod tests { #[cfg(test)] ... }` for test modules rather than creating separate `tests.rs` files

Applied to files:

  • crates/mdk-core/src/util.rs
🧬 Code graph analysis (2)
crates/mdk-core/src/key_packages.rs (1)
crates/mdk-core/src/util.rs (1)
  • decode_content (142-156)
crates/mdk-core/src/welcomes.rs (1)
crates/mdk-core/src/util.rs (1)
  • decode_content (142-156)
🔇 Additional comments (2)
crates/mdk-core/src/util.rs (1)

162-210: ContentEncoding tests provide good coverage of new behavior

The new tests exercise hex/base64 round‑trips, invalid input handling, ambiguous strings, and tag value round‑trip, which aligns well with the new decode_content API and tag‑based encoding selection.

crates/mdk-core/src/key_packages.rs (1)

642-666: Tests correctly enforce 7‑tag structure including encoding

The updated tests (test_key_package_creation_and_parsing and test_complete_tag_structure_mip00_compliance) now assert a 7‑tag structure and explicitly check that the last tag is the custom encoding tag, which matches the new create_key_package_for_event contract and spec text in the comments.

Also applies to: 861-863, 895-899

- Always include ["encoding", "hex"] or ["encoding", "base64"] tag
- Revert to fixed-size [Tag; 7] array instead of Vec<Tag>
- Remove wrapper methods, inline decode_content calls
- Add test for ContentEncoding::from_tags
@mubarakcoded mubarakcoded force-pushed the fix/encoding-tag-improvements branch from 9dc8f16 to 7427a6d Compare December 7, 2025 03:00
@github-actions
Copy link

github-actions bot commented Dec 7, 2025

⚠️ Coverage: 87.03% → 87.03% (0.00%)

Copy link
Contributor

@jgmontoya jgmontoya left a comment

Choose a reason for hiding this comment

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

Looks good, leaving just a very minor comment but approved so you can merge after addressing

@github-actions
Copy link

github-actions bot commented Dec 7, 2025

✅ Coverage: 87.03% → 87.04% (+0.01%)

@mubarakcoded mubarakcoded merged commit f069d8b into master Dec 10, 2025
11 checks passed
@jgmontoya jgmontoya deleted the fix/encoding-tag-improvements branch December 10, 2025 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants