0xMiden / 0xMiden/note-transport-service

Slim down TransportNote: replace NoteHeader with (NoteId, NoteTag)

Open
#92 2 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Rust
Stars
3
Forks
10
Avg merge
2h 23m
Merged PRs (30d)
4

Description

## Context

Follow-up to [#81](https://github.com/0xMiden/note-transport-service/pull/81), which added `after_block_num` to `TransportNote`. During review, [@igamigo](https://github.com/igamigo) and [@WiktorStarczewski](https://github.com/WiktorStarczewski) raised a larger refactor of the message format. The team decided in sync to keep #81 focused on the block number and defer this to its own PR so the wire-format change gets proper thought. This is that tracking issue.

## Motivation

`TransportNote` currently carries the full serialized `NoteHeader` in field 1. `NoteHeader` is `{ NoteId, NoteMetadata }`, and:

- It is partly redundant. `NoteId` is a commitment derived from the note's recipient and details commitment, and `details` (field 2) already lets the recipient recompute that commitment. So shipping the full header alongside `details` duplicates information.
- It leaks more than the relay needs. `NoteMetadata` includes the sender, note type, tag, etc. The untrusted relay only needs the tag (to index/serve by tag) and enough to let the recipient match the note — it does not need the sender in the clear.

## Proposed change

Replace the `header` field with two explicit fields: `NoteId` and `NoteTag`.

Rationale (from [@igamigo](https://github.com/igamigo)): the chain is scanned by tag, and a candidate note is confirmed by recomputing/matching its `NoteId`. Sending only `(NoteId, NoteTag)` is sufficient for delivery and matching, hides the rest of the metadata (notably the sender) from the service and the network, and saves bandwidth.

This also lets the service stop parsing the header on `SendNote`. Today it deserializes the `NoteHeader` to derive the `id` and `tag` storage columns (see `NewNote::from` in `crates/node/src/database/sqlite/models.rs` and the proto comment "Includes the full header for NoteId, NoteTag access"). With explicit fields, the service stores them directly and never needs to understand note internals.

## What needs to be done

- Proto: drop `bytes header = 1`; add explicit `NoteId` and `NoteTag` fields to `TransportNote`. Update the message-level doc comment.
- Service: stop deserializing the header; read `note_id` / `tag` from the new fields for the storage columns. Drop the `header` DB column (migration).
- Client ([miden-client](https://github.com/0xMiden/miden-client), tracked separately in [#2108](https://github.com/0xMiden/miden-client/issues/2108)): send `(NoteId, NoteTag)` instead of the header, and reconstruct/verify on the receive side.
- Tests: cover the new failure mode below (inconsistent `NoteId` only surfaces at commitment-scan time).

## Open questions / caveats

Raised by [@WiktorStarczewski](https://github.com/WiktorStarczewski):

1. Breaking wire change. This is not additive — it removes field 1 and changes the message shape, so it requires a coordinated service + client rollout (unlike #81, which was backward-compatible).
2. Verification moves from import-time to commit-time. Today a malformed note is detectable the moment it's fetched (the header parses or it doesn't). With `(NoteId, NoteTag)`, an inconsistent `NoteId` is only detectable once the commitment scan runs. The end state matches today's "sender never landed the tx" case (the note parks in `Expected`) and adds no new trust assumption — the sender controls delivery either way — but the failure mode shifts and tests should cover it.
3. Sender unknown until commitment. A wallet can currently show "incoming note from X" at fetch time from the header metadata. With the minimal format, sender/metadata only land after the commitment scan. Because `after_block_num` (from #81) makes that scan deterministic and immediate, the gap is ~one sync cycle — judged acceptable, not a dealbreaker.

## Out of scope

The race condition itself is already fixed by `after_block_num` in #81. This issue is purely about slimming the message format for privacy and bandwidth.

Contributor guide

Open the contributing guide

Research direction

The change is in the protobuf definition of TransportNote and its handling in the service. Start with the proto file to replace the header field with explicit NoteId and NoteTag fields. Update the database models in crates/node/src/database/sqlite/models.rs to stop deserializing the header and use the new fields directly, and write a migration to drop the header column. Tests need to cover the new verification failure mode where an inconsistent NoteId is only caught at commitment scan time.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, databases
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.