Skip to content

notes: track transaction note metadata#4218

Open
benma wants to merge 1 commit into
BitBoxSwiss:masterfrom
benma:txnote-tombstone
Open

notes: track transaction note metadata#4218
benma wants to merge 1 commit into
BitBoxSwiss:masterfrom
benma:txnote-tombstone

Conversation

@benma

@benma benma commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Empty notes become tombstones, and we add modified timestamps. This is necessary so BitBoxSync can merge conflicts and sync deletions.

@benma benma requested a review from bznein July 6, 2026 21:19
@benma benma requested a review from a team as a code owner July 6, 2026 21:19
@benma benma force-pushed the txnote-tombstone branch from 6b9b2b1 to 54c5045 Compare July 6, 2026 22:47

@bznein bznein left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Codex pointed out this:

The metadata/tombstone model mostly works, but blank notes for transactions that never had notes are now recorded as deletion tombstones through existing send paths. That
can corrupt sync semantics and should be fixed before merging.

Review comment:

  • [P2] Avoid tombstones for missing blank notes — /home/bznein-coding-agent/agent-
    work/bitbox-wallet-app/backend/accounts/notes/notes.go:108-113
    When note == "" and the txID is absent, this now marks the note as changed and
    persists an empty entry with fresh ModifiedAt. Current BTC/ETH send paths call
    SetTxNote(..., txNote) unconditionally, so sending without a note creates a
    tombstone for a note the user never deleted; callers of TransactionNoteEntries()
    then cannot distinguish this from an actual deletion and may propagate false
    deletes. Keep missing+empty as a no-op, or skip blank send notes before calling
    SetTxNote.

}

func (notes *Notes) setTransactionMetadata(txID string, metadata TransactionMetadata) {
if !metadata.ModifiedAt.IsZero() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[nit] you can use the isZero method defined above here if I'm not mistaken

if len(entry.Note) > MaxNoteLen {
return errp.Newf("Length of note must be smaller than %d. Got %d", MaxNoteLen, len(entry.Note))
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[nit] what if instead of early return, we log all errors?

and do something similar to

func validateTransactionNoteEntries(entries map[string]TransactionNoteEntry) error {
	var errs []error

	for _, entry := range entries {
		if len(entry.Note) > MaxNoteLen {
			errs = append(errs, errp.Newf(
				"Length of note must be smaller than %d. Got %d",
				MaxNoteLen,
				len(entry.Note),
			))
		}
	}

	if len(errs) > 0 {
		return errors.Join(errs...)
	}
	return nil
}

I don't feel particularly strong about it tbh, just an idea

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah why not. I am also considering truncating to the max length instead of failing, wdyt?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah I think that makes sense!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SetTxNote also has been failing on too large notes, so I'll leave it like this for consistency.

I applied your suggestion.

@benma benma force-pushed the txnote-tombstone branch from 54c5045 to ba7a129 Compare July 8, 2026 03:24
@benma

benma commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Codex pointed out this:

The metadata/tombstone model mostly works, but blank notes for transactions that never had notes are now recorded as deletion tombstones through existing send paths. That can corrupt sync semantics and should be fixed before merging.

Review comment:

* [P2] Avoid tombstones for missing blank notes — /home/bznein-coding-agent/agent-
  work/bitbox-wallet-app/backend/accounts/notes/notes.go:108-113
  When note == "" and the txID is absent, this now marks the note as changed and
  persists an empty entry with fresh ModifiedAt. Current BTC/ETH send paths call
  SetTxNote(..., txNote) unconditionally, so sending without a note creates a
  tombstone for a note the user never deleted; callers of TransactionNoteEntries()
  then cannot distinguish this from an actual deletion and may propagate false
  deletes. Keep missing+empty as a no-op, or skip blank send notes before calling
  SetTxNote.

Very good catch! Fixed.

@benma benma requested a review from bznein July 8, 2026 03:25
Empty notes become tombstones, and we add modified timestamps. This is
necessary so BitBoxSync can merge conflicts and sync deletions.
@benma benma force-pushed the txnote-tombstone branch from ba7a129 to 6a78d8d Compare July 8, 2026 20:03
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