Skip to content

MF3-L17, I15, I16: app-session participant docs, Void-checkpoint promotion, signature canonicalization note#828

Merged
philanton merged 5 commits into
fix/audit-findings-finalx3from
fix/mf3-l17
Jun 11, 2026
Merged

MF3-L17, I15, I16: app-session participant docs, Void-checkpoint promotion, signature canonicalization note#828
philanton merged 5 commits into
fix/audit-findings-finalx3from
fix/mf3-l17

Conversation

@philanton

Copy link
Copy Markdown
Contributor

Addresses three audit findings.

MF3-L17 — single-participant app sessions (docs)

create_app_session docs claimed "at least 2 participants required", but CreateAppSession() only enforces the max participant count and quorum — a single-participant session with quorum = 1 is valid. We decided to keep single-participant app sessions, so the doc was the divergence. Updated app_session_v1/README.md to "at least 1 participant required" to match implementation.

MF3-I15 — Void channel left un-promoted on checkpoint (fix)

ChannelHub.createChannel() can emit ChannelCheckpointed before ChannelCreated for an initial non-deposit/non-withdraw state. If the checkpoint was processed while the local row was still the Void seed, HandleHomeChannelCheckpointed() bumped state_version but left the channel Void, violating the protocol invariant until the later ChannelCreated event replayed and repaired it.

Fix: treat a checkpoint on a Void home channel as evidence it is materialized on-chain and promote it to Open, backfilling any unsigned concurrent receiver head (mirrors HandleHomeChannelCreated). The later ChannelCreated then no-ops via the Status >= Open guard. Added a regression test.

MF3-I16 — stored signatures not canonicalized (docs)

channel_states.user_sig / node_sig are unbounded text and accepted signatures are persisted verbatim rather than re-encoded after verification. They may retain non-canonical / unused trailing bytes (notably around session-key payloads, and for signatures learned from on-chain events that bypass the WebSocket message-size limit). No asset-safety impact — verification still gates acceptance. Documented under Known Limitations so consumers don't assume stored signature bytes are minimal/canonical.

🤖 Generated with Claude Code

philanton and others added 3 commits June 8, 2026 12:23
Implementation enforces only the maximum participant count, so a
single-participant app session is valid. Update the create_app_session
validation docs to state "at least 1 participant required" instead of 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ChannelHub.createChannel can emit ChannelCheckpointed before ChannelCreated
for an initial non-deposit/non-withdraw state. If the checkpoint is processed
while the local row is still the Void seed, HandleHomeChannelCheckpointed bumped
state_version but left the channel Void, violating the protocol invariant until
the later ChannelCreated event replayed and repaired it.

Treat a checkpoint on a Void home channel as evidence the channel is materialized
on-chain and promote it to Open, backfilling any unsigned concurrent receiver head
(mirrors HandleHomeChannelCreated). The later ChannelCreated then no-ops via the
Status >= Open guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Accepted user_sig/node_sig values are persisted verbatim rather than
re-encoded after verification, so they may retain non-canonical or unused
trailing bytes (notably around session-key payloads, and for signatures
learned from on-chain events that bypass the WebSocket message-size limit).
Document this under Known Limitations: no asset-safety impact, but consumers
must not assume stored signature bytes are minimal or canonical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32adb7c5-fd17-402e-8eff-5147a75868c3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mf3-l17

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.

@nksazonov nksazonov changed the base branch from main to fix/audit-findings-finalx3 June 8, 2026 11:01

@nksazonov nksazonov left a comment

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.

Good job — the three audit findings are addressed correctly and the fix logic is sound; two small things to tighten before landing.

Comment thread nitronode/event_handlers/service.go Outdated
Comment thread nitronode/event_handlers/service_test.go

@ihsraham ihsraham 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.

Approving for L-17 / I-15 / I-16 closure. The docs now match the intended single-participant app-session behavior, the checkpoint path promotes only Void home channels to Open, and the stored-signature limitation is documented clearly.

Agree to Nikita's existing non-blocking notes. One small docs cleanup remains: the create-app-session README sample now shows one participant but still has two signature placeholders. That does not reopen L-17, but it is worth tightening before merge.

philanton and others added 2 commits June 10, 2026 18:48
Resolve conflict in nitronode/event_handlers/service_test.go: keep both the
Void-promotion checkpoint test (adapted to the base branch's read-under-lock
LockUserStateForHomeChannel API) and the base branch's
DoesNotReopenFinalizedChannel test.

Also fix two pre-existing breakages inherited from the base branch:
- channel_v1/submit_state_test.go referenced the removed MockActionGateway /
  actionGateway field (action gateway was deleted on base) — drop the stale line.
- channel_v1/submit_session_key_state_test.go carried a contradictory
  AllowsEmptyAssetsWithPastExpiresAt test (version-1 revoke expecting success)
  alongside the new RevokeFirstSubmit_Rejected rule (version-1 revoke rejected) —
  remove the obsolete test, superseded by RevokeFirstSubmit_Rejected /
  RevokeExistingActiveKey.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- HandleHomeChannelCheckpointed: snapshot the pre-checkpoint status once and
  derive wasVoid/wasChallenged from it, so neither branch depends on the other's
  mutation order (the Void branch could otherwise flip Status to Open before
  wasChallenged is read).
- Add TestHandleHomeChannelCheckpointed_FromVoidBackfillsUnsignedReceiverHead
  covering the Void→Open arm of the head-sig backfill (transfer_receive and
  release), so dropping the `|| wasVoid` clause is caught by CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@philanton philanton merged commit 6a6ae25 into fix/audit-findings-finalx3 Jun 11, 2026
7 checks passed
@philanton philanton deleted the fix/mf3-l17 branch June 11, 2026 10:24
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.

3 participants