In this commit, we add a rapid derived fuzz test for the HtlcAuxBlob
test. This uses the rapid (randomized property testing) into Go's built
in fuzzer. This wrapper will use the fuzz stream, and pass that into
rapid where the stream is used to make structured test inputs which are
tested against the existing properties.
This can be done more widely in the codebase, we pick a simple example
to port first before tackling others.
In this commit, we enable a custom payer for the rbf coop close. This
allows us to ensure that the party that started one side of the close
flow pays the fees.
In this commit, we update the core coop close logic with the new custom
payer param. We also expand the existing unit tests to ensure that the
fee is deducted from the proper party.
This preps us for an upcoming change to the rbf coop state machine where
either party can pay for the channel fees. We also add a new test to
make sure the new function adheres to some key properties.
In this commit, we add the state transitions for the new protofsm based
RBF chan closer. The underlying protocol is a new asymmetric co-op close
process, wherein either side can initiate a chan closer, and use their
settled funds to pay for fees within the channel.
In this commit, we add the ability to specify a custom sequence for a
co-op close tx. This'll come in handy later as the new co-op close
process allows a party to set a custom sequence.
In this commit, we add the initial set of states for the new protofsm
based rbf chan closer. A diagram outlining the new states and their
transitions can be found here:
https://gist.github.com/Roasbeef/acc4ff51b9dff127230228a05553cdfe.
Unlike the existing co-op close process, this co-op close can be
restarted at anytime if either side sends a shutdown message. From
there, we'll each obtain a new RBF'd version that can be re-broadcasted.
This commit creates the set of states, along with the environment that
our state machine will use to drive itself forward.
In this commit, we fix an existing race in the new `protofsm` state
machine executor tests.
The race would appear as such:
```
--- FAIL: TestStateMachineMsgMapper (0.00s)
state_machine_test.go:165:
Error Trace:/home/runner/work/lnd/lnd/protofsm/state_machine_test.go:165
/home/runner/work/lnd/lnd/protofsm/state_machine_test.go:451
Error: Object expected to be of type *protofsm.dummyStateStart, but was *protofsm.dummyStateFin
Test: TestStateMachineMsgMapper
FAIL
FAILgithub.com/lightningnetwork/lnd/protofsm0.116s
FAIL
```
This race condition was triggered as before we would start the state
machine _then_ register for notifications. In `Start` we emit the
starting event, then enter the main loop. If that event gets emitted
before our subscription, then we'll miss the event, as the terminal
event will be the only one received.
We fix this by registering for the events before the daemon has started.
In this commit, we update the execution logic to allow multiple internal
events to be emitted. This is useful to handle potential out of order
state transitions, as they can be cached, then emitted once the relevant
pre-conditions have been met.
In this commit, we add the SpendMapper which allows callers to create
custom spent events. Before this commit, the caller would be able to
have an event sent to them in the case a spend happens, but that event
wouldn't have any of the relevant spend details.
With this new addition, the caller can specify how to take a generic
spend event, and transform it into the state machine specific spend
event.
In this commit, we add the ability for the state machine to consume wire
messages. This'll allow the creation of a new generic message router
that takes the place of the current peer `readHandler` in an upcoming
commit.
In this commit, we add an optional daemon event that can be specified to
dispatch during init. This is useful for instances where before we
start, we want to make sure we have a registered spend/conf notification
before normal operation starts.
We also add new unit tests to cover this, and the prior spend/conf event
additions.
In this PR, we create a new package, `protofsm` which is intended to
abstract away from something we've done dozens of time in the daemon:
create a new event-drive protocol FSM. One example of this is the co-op
close state machine, and also the channel state machine itself.
This packages picks out the common themes of:
* clear states and transitions between them
* calling out to special daemon adapters for I/O such as transaction
broadcast or sending a message to a peer
* cleaning up after state machine execution
* notifying relevant callers of updates to the state machine
The goal of this PR, is that devs can now implement a state machine
based off of this primary interface:
```go
// State defines an abstract state along, namely its state transition function
// that takes as input an event and an environment, and returns a state
// transition (next state, and set of events to emit). As state can also either
// be terminal, or not, a terminal event causes state execution to halt.
type State[Event any, Env Environment] interface {
// ProcessEvent takes an event and an environment, and returns a new
// state transition. This will be iteratively called until either a
// terminal state is reached, or no further internal events are
// emitted.
ProcessEvent(event Event, env Env) (*StateTransition[Event, Env], error)
// IsTerminal returns true if this state is terminal, and false otherwise.
IsTerminal() bool
}
```
With their focus being _only_ on each state transition, rather than all
the boiler plate involved (processing new events, advancing to
completion, doing I/O, etc, etc).
Instead, they just make their states, then create the state machine
given the starting state and env. The only other custom component needed
is something capable of mapping wire messages or other events from the
"outside world" into the domain of the state machine.
The set of types is based on a pseudo sum type system wherein you
declare an interface, make the sole method private, then create other
instances based on that interface. This restricts call sites (must pass
in that interface) type, and with some tooling, exhaustive matching can
also be enforced via a linter.
The best way to get a hang of the pattern proposed here is to check out
the tests. They make a mock state machine, and then use the new executor
to drive it to completion. You'll also get a view of how the code will
actually look, with the focus being on the: input event, current state,
and output transition (can also emit events to drive itself forward).
In this commit, we complete a recently added feature by ensuring that
even if we go through the RBF loop to create a txn, that we still
populate the `outpointToIndex` map. Unit tests have been updated to
ensure this is always set as expected.
In this commit, we start to print the PID of node's we created within an
itest. This is useful when debugging itests with `dlv` by attaching to a
given node. By printing out the PID, we facilitate such debugging
attempts.
In this commit, we update the `Budget()` call to factor in the
`extraBudget` value. Otherwise, when we go to intialize the fee
function, we won't factor in the extra budget, and will determine that
we can't broadcast/bump.
In this commit, we expand the `NotifyBroadcast` to include an outpoint
index. This is useful as it indicates the index of a given required tx
out input.
With this commit, we update all the resolvers to pass in the new htlc
resolution blobs. Along the way, we remove the old blocking guard on
this resolution logic for HTLCs with blobs.
In this commit, we add the set of HtlcBlobs to the taprootBriefcase
struct. This new field will store all the resolution blobs for a given
HTLC. We also add some new property based tests along the way for
adequate test coverage.
In this commit, we add a new method to obtain an option of a preimage to
the input.Input struct. This is useful for callers that have an Input,
and want to optionally obtain the preimage.
In this commit, we populate the resolution blobs for the incoming and
outgoing HTLCs. We take care to populate the AuxSigDesc with the correct
information, as we need to pass along the second-level aux signature and
also sign desc along with it.
Similar to the other blobs we have for the commitment output force close
resolution, these blobs will be used to ensure that we have everything
needed to sweep aux HTLCs.
In this commit, we add some additional attributes to the ResolutionReq
struct. These will be used to make sure that we can properly handle all
the HTLC variants, on chain.
The `AuxSigDesc` will be used to communicate if an HTLC needs to go to
the second level or not. It contains the second-level sig information
needed to finalize a broadcast to the second level.
Similar to the sweeper, when we're about to make a new breach
transaction, we ask the sweeper for a new change address, if it has one.
Then when we go to publish, we notify broadcast.
In this commit, we start to use the AuxSweeper (if present) to obtain a
new extra change addr we should add to the sweeping transaction. With
this, we'll take the set of inputs and our change addr, and then maybe
gain a new change addr to add to the sweep transaction.
The extra change addr will be treated as an extra required tx out,
shared across all the relevant inputs. This'll also be used in
NeedWalletInput to make sure that we add an extra input if needed to be
able to pay for the change addr.
In this commit, we add a new AuxSweeper interface. This'll take a set of
inputs, and a change addr for the sweep transaction, then optionally
return a new sweep output to be added to the sweep transaction.
We also add a new NotifyBroadcast method. This'll be used to notify
that we're _about_ to broadcast a sweeping transaction. The set of
inputs is passed in, which allows the caller to prepare for the ultimate
broadcast of the sweeping transaction.
We also add ExtraTxOut to BumpRequest pass fees to NotifyBroadcast. This
allows the callee to know the total fee of the sweeping transaction.
In this commit, we refactor all the other constructors for the input to
use MakeBaseInput. We also add a new set of functional options as well.
This'll be useful later on to ensure that new options are properly
applied to all the input types.
This will be used by external callers to modify the way we resolve
contracts on chain. For a given contract, we'll store an extra "blob",
that will later be presented during the sweeping phase.
In this commit, we remove the global application level lock from the
postgres backend. This lock prevents multiple write transactions from
happening at the same time, and will also block a writer if a read is on
going. Since this lock was added, we know always open DB connections
with the strongest level of concurrency control available:
`LevelSerializable`. In concert with the new auto retry logic, we ensure
that if db transactions conflict (writing the same key/row in this
case), then the tx is retried automatically.
Removing this lock should increase perf for the postgres backend, as now
concurrent write transactions can proceed, being serialized as needed.
Rather then trying to handle concurrency at the application level, we'll
set postgres do its job, with the application only needing to retry as
necessary.
In this commit, we move to add the internal key to the delivery addr. This way, we give the aux chan closer the extra information it may need to properly augment the normal co-op close process.