Skip to content

trees/checkpoint: Add checkpoint.Checkpoint#8830

Open
beautifulentropy wants to merge 2 commits into
mainfrom
trees-checkpoint
Open

trees/checkpoint: Add checkpoint.Checkpoint#8830
beautifulentropy wants to merge 2 commits into
mainfrom
trees-checkpoint

Conversation

@beautifulentropy

@beautifulentropy beautifulentropy commented Jun 30, 2026

Copy link
Copy Markdown
Member

Add Checkpoint to represent a tlog-checkpoint note body, with .String() to serialize it and .Marshal() to serialize with field validation. Add Parse() to parse an unsigned body and Open() to verify a signed note and parse its body into a Checkpoint.

A note to reviewers: this package and its tests were written with assistance from Claude Opus 4.8. That being said, it has been reviewed and extensively revised by myself before submission.

@beautifulentropy beautifulentropy marked this pull request as ready for review June 30, 2026 17:11
@beautifulentropy beautifulentropy requested a review from a team as a code owner June 30, 2026 17:11
// serializing.
//
// https://c2sp.org/tlog-checkpoint
func (c Checkpoint) String() string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The Checkpoint type contains both a slice (Extensions) and a potentially-large array (Tree.Hash), so we should probably not be passing Checkpoints around by value. These should be pointer receivers, and Parse should return a *Checkpoint.


// validNoteLine reports whether s is a valid signed-note line: UTF-8 with no
// control character below U+0020.
func validNoteLine(s string) bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are checkpoints the only kind of signed note we're going to be producing or parsing? If not, then this and other helpers should probably be in a separate note package.

return "", errors.New("empty checkpoint origin")
}
if !validNoteLine(c.Origin) {
return "", errors.New("checkpoint origin contains a control character or invalid UTF-8")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There'd be no need for this verbose "or" error line if validNoteLine returned a more-specific error itself. It would also allow you to avoid repeating this same error message several times below.

return "", errors.New("checkpoint extension line contains a control character or invalid UTF-8")
}
}
return c.String(), nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure I love this relationship between String() and Marshal(). I like having both methods! But:
a) I think that most callers of .String() (e.g. test got/want error output) expect the result of that method to be single-line; and
b) Having two ways to get the exact same result, one of which is unsafe, feels unsafe to me.

How would you feel about having .String() instead return a purposefully non-compliant single-line result, specifically for internal debugging use, while .Marshal() constructs the actual format?

// verifiers.
//
// https://c2sp.org/signed-note
func Open(signedNote []byte, verifiers note.Verifiers) (Checkpoint, *note.Note, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Who are the prospective callers of this function? Why do they want access to the underlying Note, and not just the Checkpoint? They're just different in-memory views onto the same text, right?

@aarongable aarongable requested review from ezekiel and jsha July 3, 2026 00:50
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