This fixes an issue in the itests in the restart case. We'd see an error
like:
```
2025-03-12 23:41:10.754 [ERR] PFSM state_machine.go:661: FSM(rbf_chan_closer(2f20725d9004f7fda7ef280f77dd8d419fd6669bda1a5231dd58d6f6597066e0:0)): Unable to apply event err="invalid state transition: received *chancloser.SendOfferEvent while in ClosingNegotiation(local=LocalOfferSent(proposed_fee=0.00000193 BTC), remote=ClosePending(txid=07229915459cb439bdb8ad4f5bf112dc6f42fca0192ea16a7d6dd05e607b92ae, party=Remote, fee_rate=1 sat/vb))"
```
We resolve this by waiting to send in the new request unil the old one
has been completed.
The itest has both sides try to close multiple times, each time with
increasing fee rates. We also test the reconnection case, bad RBF
updates, and instances where the local party can't actually pay for
fees.
In this commit, we alter the existing co-op close flow to enable RBF
bumps after re connection. With the new RBF close flow, it's possible
that after a success round _and_ a re connection, either side wants to do
another fee bump. Typically we route these requests through the switch,
but in this case, the link no longer exists in the switch, so any
requests to fee bump again would find that the link doesn't exist.
In this commit, we implement a work around wherein if we have an RBF
chan closer active, and the link isn't in the switch, then we just route
the request directly to the chan closer via the peer. Once we have the
chan closer, we can use the exact same flow as prior.
We'll properly handle a protocol error due to user input by halting, and
sending the error back to the user.
When a user goes to issue a new update, based on which state we're in,
we'll either kick off the shutdown, or attempt a new offer. This matches
the new spec update where we'll only send `Shutdown` once per
connection.
In this commit, we extend `CloseChannelAssertPending` with new args that
returns the raw close status update (as we have more things we'd like to
assert), and also allows us to pass in a custom fee rate.
In this commit, we fully integrate the new RBF close state machine into
the peer.
For the restart case after shutdown, we can short circuit the existing
logic as the new FSM will handle retransmitting the shutdown message
itself, and doesn't need to delegate that duty to the link.
Unlike the existing state machine, we're able to restart the flow to
sign a coop close with a new higher fee rate. In this case, we can now
send multiple updates to the RPC caller, one for each newly singed coop
close transaction.
To implement the async flush case, we'll launch a new goroutine to wait
until the state machine reaches the `ChannelFlushing` state, then we'll
register the hook. We don't do this at start up, as otherwise the
channel may _already_ be flushed, triggering an invalid state
transition.
In this commit, we add a new composite chanCloserFsm type. This'll allow
us to store a single value that might be a negotiator or and rbf-er.
In a follow up commit, we'll use this to conditionally create the new
rbf closer.
In the next commit, we'll start checking feature bits to decide how to
init the chan closer.
In the future, we can move the current chan closer handling logic into
an `MsgEndpoint`, which'll allow us to get rid of the explicit chan
closer map and direct handling.
In this commit, we add an upfront check for `SendWhen` predicates before
deciding to launch a goroutine. This ensures that when a message comes
along that is already ready to send, we do the send in a synchronous
manner.
In this commit, we update the RBF state machine to handle early offer
cases. This can happen if after we send out shutdown (to kick things
off), the remote party sends their offer early. This can also happen if
their outgoing shutdown (to ACK ours) was delayed for w/e reason, and we
get their offer first.
The alternative was to modify the state machine itself, but we feel that
handling this early case is better in line with the Robustness principle.
In this commit, we implement a special case for OP_RETURN scripts
outlined in the spec. If a party decides that its output will be too
small even after the dust check, then they can opt to set it to zero by sending an `OP_RETURN` as their script.
In this commit, we implement the latest version of the RBF loop as
described in the spec. We remove the self loop back based on sending or
receiving shutdown. Instead, from the ClosePending state, we can trigger
a new loop by sending SendOfferEvent (we bump), or OfferReceivedEvent
(they bump).
We also update the rbf state machine w/ the new close addr logic. This
log ensures that the remote party always sends our current address, and
that if they send a new address, we'll update our view of it, and
counter sign the correct transaction.
We also add a CloseErr state. With this new state, we can ensure that
we're able to properly report errors back to the RPC client, and also
optionally force a reconnection or send a warning to the remote party.
In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.
The tests have been updated accordingly.
We don't return an error on broadcast fail as the broadcast might have
failed due to insufficient fees, or inability to be replaced, which may
happen when one side attempts to unnecessarily bump their coop close
fee.
In this commit, we add an implementation of a new interface the rbf coop
state machine needs. We take care to accept interfaces everywhere, to
make this easier to test, and decouple from the concrete types we'll end
up using elsewhere.
In this commit, we change LinkDirection to be a type alias. This makes
creating wrapper structs/interfaces easier, as we don't need to leak
htlcswitch.LinkDirection, instead we can accept a bool.