Skip to content

smite: check upfront_shutdown_script on shutdown - #267

Draft
ekzyis wants to merge 3 commits into
lnfuzz:masterfrom
ekzyis:upfront-shutdown-script
Draft

ekzyis wants to merge 3 commits into
lnfuzz:masterfrom
ekzyis:upfront-shutdown-script

Conversation

@ekzyis

@ekzyis ekzyis commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

based on #266, related to #98

An `upfront_shutdown_script` in `open_channel` or `accept_channel` binds
its sender to that exact `scriptpubkey` when closing the channel, but
neither commitment was recorded, so no `shutdown` was checked against
them.

Record both from the negotiated messages and have `ShutdownOracle` also
flag the target if:

* it replied to a `shutdown` of ours that broke our own commitment,
  which BOLT 2 requires it to fail the connection over instead
* its own `scriptpubkey` differs from what it committed to

A commitment only binds once `option_upfront_shutdown_script` is
negotiated, and a zero-length script commits to nothing, so neither
check applies in those cases. Our side is read from the `shutdown` we
recorded sending, so a target closing the channel first breaks no
commitment of ours.

RecvShutdown consumes the SentShutdown of a previous SendShutdown and
waits for the target's `shutdown` on the given channel. It returns that
channel's scriptpubkey, or empty bytes if no `shutdown` was received.

The target can send `shutdown` at any time and on any channel, so a
received one is recorded into its channel's state like `channel_ready`,
and explicit receives skip past it instead of failing. SendShutdown
records the script we sent, which is what makes a reply expected there,
and RecvShutdown reads the reply from channel state, so one recorded
before it ran is reported just the same.

BOLT 2 lets the target warn about a non-standard scriptpubkey instead of
replying, but every implementation except LDK disconnects afterwards and
LDK acts as if the `shutdown` never came, so a warning just ends
execution like any other unexpected message.

A target that has not sent `channel_ready` may ignore our `shutdown`, so
RecvShutdown is a no-op until it has. That gives up coverage of targets
which do reply before then, in exchange for not spending a receive
timeout on every target which doesn't.
A received `shutdown` was recorded against its channel without being
judged, so a target naming a channel we never funded, replying on a
channel it should have failed, or using a `scriptpubkey` it was not
allowed to, went unreported.

Add a `ShutdownOracle` beside the other message oracles, evaluated by
`handle_implicit` before the `shutdown` is recorded, and report its
findings as `InvalidShutdown`. It flags the target if:

* the `shutdown` is for a channel we never funded
* we sent an invalid signature, so the target should have failed the
  channel instead of replying
* its `scriptpubkey` isn't a standard form for the negotiated features
An `upfront_shutdown_script` in `open_channel` or `accept_channel` binds
its sender to that exact `scriptpubkey` when closing the channel, but
neither commitment was recorded, so no `shutdown` was checked against
them.

Record both from the negotiated messages and have `ShutdownOracle` also
flag the target if:

* it replied to a `shutdown` of ours that broke our own commitment,
  which BOLT 2 requires it to fail the connection over instead
* its own `scriptpubkey` differs from what it committed to

A commitment only binds once `option_upfront_shutdown_script` is
negotiated, and a zero-length script commits to nothing, so neither
check applies in those cases. Our side is read from the `shutdown` we
recorded sending, so a target closing the channel first breaks no
commitment of ours.
@ekzyis
ekzyis force-pushed the upfront-shutdown-script branch from a90fc27 to ca92cf2 Compare October 22, 2026 22:28
@ekzyis
ekzyis marked this pull request as draft October 22, 2026 22:30
@ekzyis

ekzyis commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

ca92cf2: rebased on top of f2da440 (#266). Keeping this as a draft until I'm happy with all changes.

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.

1 participant